<commit_before>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <boost/python.hpp>
#include <boost/optional.hpp>

#include <nix.hpp>
#include <accessors.hpp>
#include <transmorgify.hpp>

#include <PyEntity.hpp>

using namespace nix;
using namespace boost::python;

namespace nixpy {

// Units

void setUnits(MultiTag& dt, const std::vector<std::string>& units) {
    if (!units.empty())
        dt.units(units);
    else
        dt.units(boost::none);
}

// Extents

boost::optional<DataArray> getExtents(MultiTag& dt) {
     DataArray da = dt.extents();
     if (da)
         return boost::optional<DataArray>(da);
     else
         return boost::none;
}

void setExtents(MultiTag& dt, const boost::optional<DataArray>& data) {
    if (data)
        dt.extents(*data);
    else
        dt.extents(boost::none);
}

// getter for Reference

boost::optional<DataArray> getReferenceById(const MultiTag& st, const std::string& id) {
    DataArray da = st.getReference(id);

    return da ? boost::optional<DataArray>(da) : boost::none;
}

boost::optional<DataArray> getReferenceByPos(const MultiTag& st, size_t index) {
    DataArray da = st.getReference(index);

    return da ? boost::optional<DataArray>(da) : boost::none;
}

// operations for Feature

Feature createNewFeature(MultiTag& dt, const DataArray &data, LinkType link_type) {
    Feature f = dt.createFeature(data, link_type);

    return f;
}

boost::optional<Feature> getFeatureById(const MultiTag& st, const std::string& id) {
    Feature f = st.getFeature(id);

    return f ? boost::optional<Feature>(f) : boost::none;
}

boost::optional<Feature> getFeatureByPos(const MultiTag& st, size_t index) {
    Feature f = st.getFeature(index);

    return f ? boost::optional<Feature>(f) : boost::none;
}

void PyMultiTag::do_export() {

    PyEntityWithSources<base::IMultiTag>::do_export("MultiTag");

    class_<MultiTag, bases<base::EntityWithSources<base::IMultiTag>>>("MultiTag")

        .add_property("positions",
                      GETTER(DataArray, MultiTag, positions),
                      REF_SETTER(DataArray, MultiTag, positions),
                      doc::multi_tag_positions)
        .add_property("extents",
                      getExtents,
                      setExtents,
                      doc::multi_tag_extents)
        .add_property("units",
                      GETTER(std::vector<std::string>, MultiTag, units),
                      setUnits,
                      doc::multi_tag_units)

        // References
        .def("_add_reference_by_id", REF_SETTER(std::string, MultiTag, addReference))
        .def("_has_reference_by_id", CHECKER(std::string, MultiTag, hasReference))
        .def("_reference_count", &MultiTag::referenceCount)
        .def("_get_reference_by_id", &getReferenceById)
        .def("_get_reference_by_pos", &getReferenceByPos)
        .def("_delete_reference_by_id", REMOVER(std::string, MultiTag, removeReference))

        // Features
        .def("create_feature", &createNewFeature, doc::multi_tag_create_feature)
        .def("_has_feature_by_id", CHECKER(std::string, MultiTag, hasFeature))
        .def("_feature_count", &MultiTag::featureCount)
        .def("_get_feature_by_id", &getFeatureById)
        .def("_get_feature_by_pos", &getFeatureByPos)
        .def("_delete_feature_by_id", REMOVER(std::string, MultiTag, deleteFeature))

        // Other
        .def("__str__", &toStr<MultiTag>)
        .def("__repr__", &toStr<MultiTag>)
        ;

    to_python_converter<std::vector<MultiTag>, vector_transmogrify<MultiTag>>();
    to_python_converter<boost::optional<MultiTag>, option_transmogrify<MultiTag>>();
}

}
<commit_msg>MulitTag: export retrieveData (as retrieve_data)<commit_after>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <boost/python.hpp>
#include <boost/optional.hpp>

#include <nix.hpp>
#include <accessors.hpp>
#include <transmorgify.hpp>

#include <PyEntity.hpp>

using namespace nix;
using namespace boost::python;

namespace nixpy {

// Units

void setUnits(MultiTag& dt, const std::vector<std::string>& units) {
    if (!units.empty())
        dt.units(units);
    else
        dt.units(boost::none);
}

// Extents

boost::optional<DataArray> getExtents(MultiTag& dt) {
     DataArray da = dt.extents();
     if (da)
         return boost::optional<DataArray>(da);
     else
         return boost::none;
}

void setExtents(MultiTag& dt, const boost::optional<DataArray>& data) {
    if (data)
        dt.extents(*data);
    else
        dt.extents(boost::none);
}

// getter for Reference

boost::optional<DataArray> getReferenceById(const MultiTag& st, const std::string& id) {
    DataArray da = st.getReference(id);

    return da ? boost::optional<DataArray>(da) : boost::none;
}

boost::optional<DataArray> getReferenceByPos(const MultiTag& st, size_t index) {
    DataArray da = st.getReference(index);

    return da ? boost::optional<DataArray>(da) : boost::none;
}

// operations for Feature

Feature createNewFeature(MultiTag& dt, const DataArray &data, LinkType link_type) {
    Feature f = dt.createFeature(data, link_type);

    return f;
}

boost::optional<Feature> getFeatureById(const MultiTag& st, const std::string& id) {
    Feature f = st.getFeature(id);

    return f ? boost::optional<Feature>(f) : boost::none;
}

boost::optional<Feature> getFeatureByPos(const MultiTag& st, size_t index) {
    Feature f = st.getFeature(index);

    return f ? boost::optional<Feature>(f) : boost::none;
}

void PyMultiTag::do_export() {

    PyEntityWithSources<base::IMultiTag>::do_export("MultiTag");

    class_<MultiTag, bases<base::EntityWithSources<base::IMultiTag>>>("MultiTag")

        .add_property("positions",
                      GETTER(DataArray, MultiTag, positions),
                      REF_SETTER(DataArray, MultiTag, positions),
                      doc::multi_tag_positions)
        .add_property("extents",
                      getExtents,
                      setExtents,
                      doc::multi_tag_extents)
        .add_property("units",
                      GETTER(std::vector<std::string>, MultiTag, units),
                      setUnits,
                      doc::multi_tag_units)

        // References
        .def("_add_reference_by_id", REF_SETTER(std::string, MultiTag, addReference))
        .def("_has_reference_by_id", CHECKER(std::string, MultiTag, hasReference))
        .def("_reference_count", &MultiTag::referenceCount)
        .def("_get_reference_by_id", &getReferenceById)
        .def("_get_reference_by_pos", &getReferenceByPos)
        .def("_delete_reference_by_id", REMOVER(std::string, MultiTag, removeReference))

        // Features
        .def("create_feature", &createNewFeature, doc::multi_tag_create_feature)
        .def("_has_feature_by_id", CHECKER(std::string, MultiTag, hasFeature))
        .def("_feature_count", &MultiTag::featureCount)
        .def("_get_feature_by_id", &getFeatureById)
        .def("_get_feature_by_pos", &getFeatureByPos)
        .def("_delete_feature_by_id", REMOVER(std::string, MultiTag, deleteFeature))

        // Data
        .def("retrieve_data", &MultiTag::retrieveData)

        // Other
        .def("__str__", &toStr<MultiTag>)
        .def("__repr__", &toStr<MultiTag>)
        ;

    to_python_converter<std::vector<MultiTag>, vector_transmogrify<MultiTag>>();
    to_python_converter<boost::optional<MultiTag>, option_transmogrify<MultiTag>>();
}

}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <errno.h>
#include <QtWidgets>

#include "p6vxapp.h"

#ifndef NOJOYSTICK
//SDL使用時にビルドを通すのに必要
#undef main
#endif

///////////////////////////////////////////////////////////
// メイン
///////////////////////////////////////////////////////////
int main( int argc, char *argv[] )
{
	//X11の場合用
	QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
#if QT_VERSION >= 0x050700
#ifndef ANDROID
	// AndroidではAA_EnableHighDpiScalingを設定するとメニューの座標がおかしくなる
	QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#endif
	P6VXApp app(argc, argv);

	QCommandLineParser parser;
	QCommandLineOption safeModeOption(QStringList() << "s" << "safemode", "Safe Mode");
	parser.addOption(safeModeOption);
	parser.process(app);
	bool safeMode = parser.isSet(safeModeOption);
	app.enableSafeMode(safeMode);

#ifdef ANDROID
	// AndroidではFusion以外のスタイルでは表示が崩れるので明示的に指定する。
	app.setStyle(QStyleFactory::create("Fusion"));
	app.setCustomRomPath(CUSTOMROMPATH);
#endif

	QLocale locale;
	QString lang = locale.uiLanguages()[0];
	QTranslator myappTranslator;

	//表示言語が日本語でない場合は英語リソースを読み込む
	if(lang != "ja-JP" && lang != "ja"){
		qDebug() << "LANG = " << lang;
		myappTranslator.load(":/translation/PC6001VX_en");
		app.installTranslator(&myappTranslator);
	} else {
#ifdef ANDROID
		QFont font = QFont("MotoyaLMaru");
		if(font.exactMatch()){
			app.setFont(font);
		}
#endif
	}

	//イベントループが始まったらp6vxapp::startup()を実行
	QMetaObject::invokeMethod(&app, "startup", Qt::QueuedConnection);

	//イベントループを開始
	return app.exec();
}
<commit_msg>Androidで日本語フォントの探索を改善<commit_after>#include <stdlib.h>
#include <errno.h>
#include <QtWidgets>

#include "p6vxapp.h"

#ifndef NOJOYSTICK
//SDL使用時にビルドを通すのに必要
#undef main
#endif

///////////////////////////////////////////////////////////
// メイン
///////////////////////////////////////////////////////////
int main( int argc, char *argv[] )
{
	//X11の場合用
	QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
#if QT_VERSION >= 0x050700
#ifndef ANDROID
	// AndroidではAA_EnableHighDpiScalingを設定するとメニューの座標がおかしくなる
	QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#endif
	P6VXApp app(argc, argv);

	QCommandLineParser parser;
	QCommandLineOption safeModeOption(QStringList() << "s" << "safemode", "Safe Mode");
	parser.addOption(safeModeOption);
	parser.process(app);
	bool safeMode = parser.isSet(safeModeOption);
	app.enableSafeMode(safeMode);

#ifdef ANDROID
	// AndroidではFusion以外のスタイルでは表示が崩れるので明示的に指定する。
	app.setStyle(QStyleFactory::create("Fusion"));
	app.setCustomRomPath(CUSTOMROMPATH);
#endif

	QLocale locale;
	QString lang = locale.uiLanguages()[0];
	QTranslator myappTranslator;

	//表示言語が日本語でない場合は英語リソースを読み込む
	if(lang != "ja-JP" && lang != "ja"){
		qDebug() << "LANG = " << lang;
		myappTranslator.load(":/translation/PC6001VX_en");
		app.installTranslator(&myappTranslator);
	} else {
#ifdef ANDROID
		QFontDatabase database;
		auto list = database.families(QFontDatabase::Japanese);
		for (auto& f : list){
			// 日本語で検索して最初に見つかったフォントを使う
			auto font = QFont(f);
			qDebug() << "using " << f;
			app.setFont(font);
			break;
		}
#endif
	}

	//イベントループが始まったらp6vxapp::startup()を実行
	QMetaObject::invokeMethod(&app, "startup", Qt::QueuedConnection);

	//イベントループを開始
	return app.exec();
}
<|endoftext|>


<commit_before>/*
 * qtfastjson (QtFastJson.cpp)
 *  Part of QtFastJSON (http://github.com/waddlesplash/qtfastjson/).
 *
 * Copyright (c) 2012 WaddleSplash
 *
 * 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.
 *
*/

#include "QtFastJson.h"

QtFastJsonDoc::QtFastJsonDoc(QObject *parent) :
    QtFastJsonObject(parent)
{
}

bool QtFastJsonDoc::readJSON(QIODevice* device)
{
    QIODevice::OpenMode o = device->openMode();
    if((o == QIODevice::ReadOnly) || (o == QIODevice::ReadWrite))
    {
        QString data = device->readAll();
        return readJSON(data);
    }
    return false;
}

bool QtFastJsonDoc::readJSON(const QString data)
{
    jsonDat = data;
    json_length = jsonDat.size();
    if(json_length == 0) { return false; }

    return parser_lexer();
}

bool QtFastJsonDoc::parser_lexer()
{
    QtFastJsonObject* curParent = this;
    QtFastJsonObject* newObj;
    QVariant newObj_Key;
    QVariant newObj_Val;

    QString in = "";
    QString reading = "key";

    for(json_loc = 0; json_loc < json_length;json_loc++) {
        json_curChar = jsonDat[json_loc];

        switch(json_curChar.toLatin1())
        {
        case '{':
        {
            in += "{";

            if(in == "{")
            { break; }
            else if(reading == "array")
            { newObj_Key = curParent->childCount(); }

            curParent = curParent->addChild(newObj_Key);
            curParent->setType(List);
            newObj_Key = "";

            reading = "key";

            break;
        }
        case '}':
            if(in.endsWith('{') && !(in.size() == 1))
            {
                in.chop(1);
                curParent = curParent->jsonParent();

                if(in.endsWith('['))
                { reading = "array"; }
                else
                { reading = "key"; }
            }
            else if(in.size() == 1)
            { return true; }
            else
            { return false; }

            break;

        case '[':
        {
            in += "[";
            if(reading == "array")
            { newObj_Key = QString::number(curParent->childCount()); }

            curParent = curParent->addChild(newObj_Key);
            curParent->setType(Array);
            newObj_Key = "";

            reading = "array";
        }
            break;
        case ']':
            if(in.endsWith('['))
            {
                in.chop(1);
                curParent = curParent->jsonParent();

                if(in.endsWith('['))
                { reading = "array"; }
                else
                { reading = "key"; }
            }
            else
            { return false; }

            break;

        case 't':
            if((reading == "value") && (jsonDat.mid(json_loc,4) == "true"))
            {
                newObj_Val = true;
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);
                json_loc += 3;

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }

            break;

        case 'f':
            if((reading == "value") && (jsonDat.mid(json_loc,5) == "false"))
            {
                newObj_Val = false;
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);
                json_loc += 4;

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }

            break;

        case 'n':
            if((reading == "value") && (jsonDat.mid(json_loc,4) == "null"))
            {
                QVariant nullVariant(QVariant::String);
                newObj = curParent->addChild(newObj_Key,nullVariant);
                newObj->setType(Variant);
                json_loc += 3;

                reading = "key";
                newObj_Key = "";
            }

            break;

        case '"':
            if(reading == "value")
            {
                newObj_Val = parser_readStr();
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }
            else if(reading == "key")
            {
                newObj_Key = parser_readStr();
            }
            else if(reading == "array")
            {
                QString newArrayVal = parser_readStr();
                newObj = curParent->addChild(curParent->childCount(),newArrayVal);
                newObj->setType(Variant);
            }

            break;

        case ':':
            reading = "value";
            break;

        default:
            if(json_curChar.isDigit() && (reading == "value"))
            {
                newObj_Val = parser_readNum();
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }
            else if(json_curChar.isDigit() && (reading == "array"))
            {
                QVariant newArrayVal = parser_readNum();
                newObj = curParent->addChild(curParent->childCount(),newArrayVal);
                newObj->setType(Variant);
            }
            break;
        }
    }
    return false;
}
QString QtFastJsonDoc::parser_readStr()
{
    if(json_curChar != '"') { return ""; }

    QString ret;

    json_loc += 1;
    while(1)
    {
        if(jsonDat[json_loc] == '\\')
        {
            json_loc += 1;
            char cur = jsonDat[json_loc].toLatin1();
            switch(cur)
            { // as per http://www.json.org/
            case 'b':
                ret += "\b";
                break;
            case 'f':
                ret += "\f";
                break;
            case 'n':
                ret += "\n";
                break;
            case 'r':
                ret += "\r";
                break;
            case 't':
                ret += "\t";
                break;
            case 'u':
                ret += QChar(jsonDat.mid(json_loc+1,4).toInt(0,16));
                json_loc += 4;
                break;
            default:
                ret += jsonDat[json_loc];
                break;
            }
        }
        else if(jsonDat[json_loc] == '"')
        {
            return ret;
        }
        else
        { ret += jsonDat[json_loc]; }
        json_loc += 1;
    }

    return ret;
}

QVariant QtFastJsonDoc::parser_readNum()
{
    QVariant ret;
    QString raw;
    int addr = jsonDat.indexOf(',',json_loc);
    if(addr == -1) { addr = jsonDat.indexOf(' ',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('\n',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('\r',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('}',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf(']',json_loc); }
    if(addr == -1) { return ""; }

    raw = jsonDat.mid(json_loc,addr-json_loc);
    ret = raw.toDouble();

    json_loc = addr;

    return ret;
}
<commit_msg>Initialize variables to nothing.<commit_after>/*
 * qtfastjson (QtFastJson.cpp)
 *  Part of QtFastJSON (http://github.com/waddlesplash/qtfastjson/).
 *
 * Copyright (c) 2012 WaddleSplash
 *
 * 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.
 *
*/

#include "QtFastJson.h"

QtFastJsonDoc::QtFastJsonDoc(QObject *parent) :
    QtFastJsonObject(parent)
{
    json_curChar = ' ';
    json_loc = 0;
    json_length = 0;
    jsonDat = "";
}

bool QtFastJsonDoc::readJSON(QIODevice* device)
{
    QIODevice::OpenMode o = device->openMode();
    if((o == QIODevice::ReadOnly) || (o == QIODevice::ReadWrite))
    {
        QString data = device->readAll();
        return readJSON(data);
    }
    return false;
}

bool QtFastJsonDoc::readJSON(const QString data)
{
    jsonDat = data;
    json_length = jsonDat.size();
    if(json_length == 0) { return false; }

    return parser_lexer();
}

bool QtFastJsonDoc::parser_lexer()
{
    QtFastJsonObject* curParent = this;
    QtFastJsonObject* newObj;
    QVariant newObj_Key;
    QVariant newObj_Val;

    QString in = "";
    QString reading = "key";

    for(json_loc = 0; json_loc < json_length;json_loc++) {
        json_curChar = jsonDat[json_loc];

        switch(json_curChar.toLatin1())
        {
        case '{':
        {
            in += "{";

            if(in == "{")
            { break; }
            else if(reading == "array")
            { newObj_Key = curParent->childCount(); }

            curParent = curParent->addChild(newObj_Key);
            curParent->setType(List);
            newObj_Key = "";

            reading = "key";

            break;
        }
        case '}':
            if(in.endsWith('{') && !(in.size() == 1))
            {
                in.chop(1);
                curParent = curParent->jsonParent();

                if(in.endsWith('['))
                { reading = "array"; }
                else
                { reading = "key"; }
            }
            else if(in.size() == 1)
            { return true; }
            else
            { return false; }

            break;

        case '[':
        {
            in += "[";
            if(reading == "array")
            { newObj_Key = QString::number(curParent->childCount()); }

            curParent = curParent->addChild(newObj_Key);
            curParent->setType(Array);
            newObj_Key = "";

            reading = "array";
        }
            break;
        case ']':
            if(in.endsWith('['))
            {
                in.chop(1);
                curParent = curParent->jsonParent();

                if(in.endsWith('['))
                { reading = "array"; }
                else
                { reading = "key"; }
            }
            else
            { return false; }

            break;

        case 't':
            if((reading == "value") && (jsonDat.mid(json_loc,4) == "true"))
            {
                newObj_Val = true;
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);
                json_loc += 3;

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }

            break;

        case 'f':
            if((reading == "value") && (jsonDat.mid(json_loc,5) == "false"))
            {
                newObj_Val = false;
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);
                json_loc += 4;

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }

            break;

        case 'n':
            if((reading == "value") && (jsonDat.mid(json_loc,4) == "null"))
            {
                QVariant nullVariant(QVariant::String);
                newObj = curParent->addChild(newObj_Key,nullVariant);
                newObj->setType(Variant);
                json_loc += 3;

                reading = "key";
                newObj_Key = "";
            }

            break;

        case '"':
            if(reading == "value")
            {
                newObj_Val = parser_readStr();
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }
            else if(reading == "key")
            {
                newObj_Key = parser_readStr();
            }
            else if(reading == "array")
            {
                QString newArrayVal = parser_readStr();
                newObj = curParent->addChild(curParent->childCount(),newArrayVal);
                newObj->setType(Variant);
            }

            break;

        case ':':
            reading = "value";
            break;

        default:
            if(json_curChar.isDigit() && (reading == "value"))
            {
                newObj_Val = parser_readNum();
                newObj = curParent->addChild(newObj_Key,newObj_Val);
                newObj->setType(Variant);

                reading = "key";
                newObj_Key = "";
                newObj_Val = "";
            }
            else if(json_curChar.isDigit() && (reading == "array"))
            {
                QVariant newArrayVal = parser_readNum();
                newObj = curParent->addChild(curParent->childCount(),newArrayVal);
                newObj->setType(Variant);
            }
            break;
        }
    }
    return false;
}
QString QtFastJsonDoc::parser_readStr()
{
    if(json_curChar != '"') { return ""; }

    QString ret;

    json_loc += 1;
    while(1)
    {
        if(jsonDat[json_loc] == '\\')
        {
            json_loc += 1;
            char cur = jsonDat[json_loc].toLatin1();
            switch(cur)
            { // as per http://www.json.org/
            case 'b':
                ret += "\b";
                break;
            case 'f':
                ret += "\f";
                break;
            case 'n':
                ret += "\n";
                break;
            case 'r':
                ret += "\r";
                break;
            case 't':
                ret += "\t";
                break;
            case 'u':
                ret += QChar(jsonDat.mid(json_loc+1,4).toInt(0,16));
                json_loc += 4;
                break;
            default:
                ret += jsonDat[json_loc];
                break;
            }
        }
        else if(jsonDat[json_loc] == '"')
        {
            return ret;
        }
        else
        { ret += jsonDat[json_loc]; }
        json_loc += 1;
    }

    return ret;
}

QVariant QtFastJsonDoc::parser_readNum()
{
    QVariant ret;
    QString raw;
    int addr = jsonDat.indexOf(',',json_loc);
    if(addr == -1) { addr = jsonDat.indexOf(' ',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('\n',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('\r',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf('}',json_loc); }
    if(addr == -1) { addr = jsonDat.indexOf(']',json_loc); }
    if(addr == -1) { return ""; }

    raw = jsonDat.mid(json_loc,addr-json_loc);
    ret = raw.toDouble();

    json_loc = addr;

    return ret;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file NMRAnetEventRegistry.cxx
 * Static declarations for handling NMRAnet events.
 *
 * @author Balazs Racz
 * @date 19 October 2013
 */

#include "nmranet/NMRAnetEventRegistry.hxx"
#include "nmranet/WriteHelper.hxx"

namespace nmranet
{

EventRegistry *EventRegistry::instance_ = nullptr;

AsyncMutex event_handler_mutex;
WriteHelper event_write_helper1;
WriteHelper event_write_helper2;
WriteHelper event_write_helper3;
WriteHelper event_write_helper4;
BarrierNotifiable event_barrier;

EventRegistry::NMRAnetEventRegistry()
{
    HASSERT(instance_ == nullptr);
    instance_ = this;
}

EventRegistry::~NMRAnetEventRegistry()
{
    HASSERT(instance_ == this);
    instance_ = nullptr;
}

// static
unsigned EventRegistry::align_mask(EventId *event, unsigned size)
{
    // example: size = 140. highest bit set is bit 7
    // example2: size = 256. highest bit set is bit 8, but it is power-of-two.
    HASSERT(event);
    if (size <= 1)
    {
        return 0;
    }
    // should be 7 in both examples
    unsigned log2 = sizeof(size) * 8 - __builtin_clz(size - 1) - 1;
    uint64_t new_event, rounded_range;
    do
    {
        ++log2;  // 8 in both examples
        rounded_range = 1ULL << log2; // 256
        new_event = *event & (~(rounded_range - 1));
        // we have to be careful for overflowing uint64 in new_event =
        // rounded_range
    } while (log2 < 64 &&
             ((new_event + (rounded_range - 1)) < (*event + (size - 1))));
    if (log2 >= 64)
    {
        new_event = 0;
        log2 = 64;
    }
    // The rounding is successful.
    *event = new_event;
    return log2;
}

}; /* namespace nmranet */
<commit_msg>fix refactor glitch.<commit_after>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file NMRAnetEventRegistry.cxx
 * Static declarations for handling NMRAnet events.
 *
 * @author Balazs Racz
 * @date 19 October 2013
 */

#include "nmranet/NMRAnetEventRegistry.hxx"
#include "nmranet/WriteHelper.hxx"

namespace nmranet
{

EventRegistry *EventRegistry::instance_ = nullptr;

AsyncMutex event_handler_mutex;
WriteHelper event_write_helper1;
WriteHelper event_write_helper2;
WriteHelper event_write_helper3;
WriteHelper event_write_helper4;
BarrierNotifiable event_barrier;

EventRegistry::EventRegistry()
{
    HASSERT(instance_ == nullptr);
    instance_ = this;
}

EventRegistry::~EventRegistry()
{
    HASSERT(instance_ == this);
    instance_ = nullptr;
}

// static
unsigned EventRegistry::align_mask(EventId *event, unsigned size)
{
    // example: size = 140. highest bit set is bit 7
    // example2: size = 256. highest bit set is bit 8, but it is power-of-two.
    HASSERT(event);
    if (size <= 1)
    {
        return 0;
    }
    // should be 7 in both examples
    unsigned log2 = sizeof(size) * 8 - __builtin_clz(size - 1) - 1;
    uint64_t new_event, rounded_range;
    do
    {
        ++log2;  // 8 in both examples
        rounded_range = 1ULL << log2; // 256
        new_event = *event & (~(rounded_range - 1));
        // we have to be careful for overflowing uint64 in new_event =
        // rounded_range
    } while (log2 < 64 &&
             ((new_event + (rounded_range - 1)) < (*event + (size - 1))));
    if (log2 >= 64)
    {
        new_event = 0;
        log2 = 64;
    }
    // The rounding is successful.
    *event = new_event;
    return log2;
}

}; /* namespace nmranet */
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-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: Erik Hallnor
 */

/**
 * @file
 * Definition of BaseCache functions.
 */

#include "mem/cache/base_cache.hh"
#include "cpu/smt.hh"
#include "cpu/base.hh"

using namespace std;

BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
                                bool _isCpuSide)
    : Port(_name), cache(_cache), isCpuSide(_isCpuSide)
{
    blocked = false;
    //Start ports at null if more than one is created we should panic
    //cpuSidePort = NULL;
    //memSidePort = NULL;
}

void
BaseCache::CachePort::recvStatusChange(Port::Status status)
{
    cache->recvStatusChange(status, isCpuSide);
}

void
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
                                       AddrRangeList &snoop)
{
    cache->getAddressRanges(resp, snoop, isCpuSide);
}

int
BaseCache::CachePort::deviceBlockSize()
{
    return cache->getBlockSize();
}

bool
BaseCache::CachePort::recvTiming(Packet *pkt)
{
    if (blocked)
    {
        DPRINTF(Cache,"Scheduling a retry while blocked\n");
        mustSendRetry = true;
        return false;
    }
    return cache->doTimingAccess(pkt, this, isCpuSide);
}

Tick
BaseCache::CachePort::recvAtomic(Packet *pkt)
{
    return cache->doAtomicAccess(pkt, isCpuSide);
}

void
BaseCache::CachePort::recvFunctional(Packet *pkt)
{
    cache->doFunctionalAccess(pkt, isCpuSide);
}

void
BaseCache::CachePort::recvRetry()
{
    Packet *pkt;
    if (!drainList.empty()) {
        //We have some responses to drain first
        bool result = true;
        while (result && !drainList.empty()) {
            result = sendTiming(drainList.front());
            if (result)
                drainList.pop_front();
        }
    }

    if (!isCpuSide)
    {
        pkt = cache->getPacket();
        bool success = sendTiming(pkt);
        DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
                pkt->getAddr(), success ? "succesful" : "unsuccesful");
        cache->sendResult(pkt, success);
        if (success && cache->doMasterRequest())
        {
            //Still more to issue, rerequest in 1 cycle
            pkt = NULL;
            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
            reqCpu->schedule(curTick + 1);
        }
    }
    else
    {
        pkt = cache->getCoherencePacket();
        bool success = sendTiming(pkt);
        if (success && cache->doSlaveRequest())
        {
            //Still more to issue, rerequest in 1 cycle
            pkt = NULL;
            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
            reqCpu->schedule(curTick + 1);
        }

    }
    return;
}
void
BaseCache::CachePort::setBlocked()
{
    assert(!blocked);
    DPRINTF(Cache, "Cache Blocking\n");
    blocked = true;
    //Clear the retry flag
    mustSendRetry = false;
}

void
BaseCache::CachePort::clearBlocked()
{
    assert(blocked);
    DPRINTF(Cache, "Cache Unblocking\n");
    blocked = false;
    if (mustSendRetry)
    {
        DPRINTF(Cache, "Cache Sending Retry\n");
        mustSendRetry = false;
        sendRetry();
    }
}

BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort)
    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
{
    this->setFlags(AutoDelete);
    pkt = NULL;
}

BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, Packet *_pkt)
    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), pkt(_pkt)
{
    this->setFlags(AutoDelete);
}

void
BaseCache::CacheEvent::process()
{
    if (!pkt)
    {
        if (!cachePort->isCpuSide)
        {
            //MSHR
            pkt = cachePort->cache->getPacket();
            bool success = cachePort->sendTiming(pkt);
            DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
                    pkt->getAddr(), success ? "succesful" : "unsuccesful");
            cachePort->cache->sendResult(pkt, success);
            if (success && cachePort->cache->doMasterRequest())
            {
                //Still more to issue, rerequest in 1 cycle
                pkt = NULL;
                this->schedule(curTick+1);
            }
        }
        else
        {
            //CSHR
            pkt = cachePort->cache->getCoherencePacket();
            bool success = cachePort->sendTiming(pkt);
            if (success && cachePort->cache->doSlaveRequest())
            {
                //Still more to issue, rerequest in 1 cycle
                pkt = NULL;
                this->schedule(curTick+1);
            }
        }
        return;
    }
    //Response
    //Know the packet to send
    pkt->result = Packet::Success;
    pkt->makeTimingResponse();
    if (!cachePort->drainList.empty()) {
        //Already blocked waiting for bus, just append
        cachePort->drainList.push_back(pkt);
    }
    else if (!cachePort->sendTiming(pkt)) {
        //It failed, save it to list of drain events
        cachePort->drainList.push_back(pkt);
    }
}

const char *
BaseCache::CacheEvent::description()
{
    return "timing event\n";
}

Port*
BaseCache::getPort(const std::string &if_name, int idx)
{
    if (if_name == "")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "functional")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "cpu_side")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "mem_side")
    {
        if (memSidePort != NULL)
            panic("Already have a mem side for this cache\n");
        memSidePort = new CachePort(name() + "-mem_side_port", this, false);
        return memSidePort;
    }
    else panic("Port name %s unrecognized\n", if_name);
}

void
BaseCache::init()
{
    if (!cpuSidePort || !memSidePort)
        panic("Cache not hooked up on both sides\n");
    cpuSidePort->sendStatusChange(Port::RangeChange);
}

void
BaseCache::regStats()
{
    Request temp_req((Addr) NULL, 4, 0);
    Packet::Command temp_cmd = Packet::ReadReq;
    Packet temp_pkt(&temp_req, temp_cmd, 0);  //@todo FIx command strings so this isn't neccessary
    temp_pkt.allocate(); //Temp allocate, all need data

    using namespace Stats;

    // Hit statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        hits[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_hits")
            .desc("number of " + cstr + " hits")
            .flags(total | nozero | nonan)
            ;
    }

    demandHits
        .name(name() + ".demand_hits")
        .desc("number of demand (read+write) hits")
        .flags(total)
        ;
    demandHits = hits[Packet::ReadReq] + hits[Packet::WriteReq];

    overallHits
        .name(name() + ".overall_hits")
        .desc("number of overall hits")
        .flags(total)
        ;
    overallHits = demandHits + hits[Packet::SoftPFReq] + hits[Packet::HardPFReq]
        + hits[Packet::Writeback];

    // Miss statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        misses[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_misses")
            .desc("number of " + cstr + " misses")
            .flags(total | nozero | nonan)
            ;
    }

    demandMisses
        .name(name() + ".demand_misses")
        .desc("number of demand (read+write) misses")
        .flags(total)
        ;
    demandMisses = misses[Packet::ReadReq] + misses[Packet::WriteReq];

    overallMisses
        .name(name() + ".overall_misses")
        .desc("number of overall misses")
        .flags(total)
        ;
    overallMisses = demandMisses + misses[Packet::SoftPFReq] +
        misses[Packet::HardPFReq] + misses[Packet::Writeback];

    // Miss latency statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        missLatency[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_miss_latency")
            .desc("number of " + cstr + " miss cycles")
            .flags(total | nozero | nonan)
            ;
    }

    demandMissLatency
        .name(name() + ".demand_miss_latency")
        .desc("number of demand (read+write) miss cycles")
        .flags(total)
        ;
    demandMissLatency = missLatency[Packet::ReadReq] + missLatency[Packet::WriteReq];

    overallMissLatency
        .name(name() + ".overall_miss_latency")
        .desc("number of overall miss cycles")
        .flags(total)
        ;
    overallMissLatency = demandMissLatency + missLatency[Packet::SoftPFReq] +
        missLatency[Packet::HardPFReq];

    // access formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        accesses[access_idx]
            .name(name() + "." + cstr + "_accesses")
            .desc("number of " + cstr + " accesses(hits+misses)")
            .flags(total | nozero | nonan)
            ;

        accesses[access_idx] = hits[access_idx] + misses[access_idx];
    }

    demandAccesses
        .name(name() + ".demand_accesses")
        .desc("number of demand (read+write) accesses")
        .flags(total)
        ;
    demandAccesses = demandHits + demandMisses;

    overallAccesses
        .name(name() + ".overall_accesses")
        .desc("number of overall (read+write) accesses")
        .flags(total)
        ;
    overallAccesses = overallHits + overallMisses;

    // miss rate formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        missRate[access_idx]
            .name(name() + "." + cstr + "_miss_rate")
            .desc("miss rate for " + cstr + " accesses")
            .flags(total | nozero | nonan)
            ;

        missRate[access_idx] = misses[access_idx] / accesses[access_idx];
    }

    demandMissRate
        .name(name() + ".demand_miss_rate")
        .desc("miss rate for demand accesses")
        .flags(total)
        ;
    demandMissRate = demandMisses / demandAccesses;

    overallMissRate
        .name(name() + ".overall_miss_rate")
        .desc("miss rate for overall accesses")
        .flags(total)
        ;
    overallMissRate = overallMisses / overallAccesses;

    // miss latency formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        avgMissLatency[access_idx]
            .name(name() + "." + cstr + "_avg_miss_latency")
            .desc("average " + cstr + " miss latency")
            .flags(total | nozero | nonan)
            ;

        avgMissLatency[access_idx] =
            missLatency[access_idx] / misses[access_idx];
    }

    demandAvgMissLatency
        .name(name() + ".demand_avg_miss_latency")
        .desc("average overall miss latency")
        .flags(total)
        ;
    demandAvgMissLatency = demandMissLatency / demandMisses;

    overallAvgMissLatency
        .name(name() + ".overall_avg_miss_latency")
        .desc("average overall miss latency")
        .flags(total)
        ;
    overallAvgMissLatency = overallMissLatency / overallMisses;

    blocked_cycles.init(NUM_BLOCKED_CAUSES);
    blocked_cycles
        .name(name() + ".blocked_cycles")
        .desc("number of cycles access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    blocked_causes.init(NUM_BLOCKED_CAUSES);
    blocked_causes
        .name(name() + ".blocked")
        .desc("number of cycles access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    avg_blocked
        .name(name() + ".avg_blocked_cycles")
        .desc("average number of cycles each access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    avg_blocked = blocked_cycles / blocked_causes;

    fastWrites
        .name(name() + ".fast_writes")
        .desc("number of fast writes performed")
        ;

    cacheCopies
        .name(name() + ".cache_copies")
        .desc("number of cache copies performed")
        ;

}
<commit_msg>Don't block responses even if the cache is blocked.<commit_after>/*
 * Copyright (c) 2003-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: Erik Hallnor
 */

/**
 * @file
 * Definition of BaseCache functions.
 */

#include "mem/cache/base_cache.hh"
#include "cpu/smt.hh"
#include "cpu/base.hh"

using namespace std;

BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
                                bool _isCpuSide)
    : Port(_name), cache(_cache), isCpuSide(_isCpuSide)
{
    blocked = false;
    //Start ports at null if more than one is created we should panic
    //cpuSidePort = NULL;
    //memSidePort = NULL;
}

void
BaseCache::CachePort::recvStatusChange(Port::Status status)
{
    cache->recvStatusChange(status, isCpuSide);
}

void
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
                                       AddrRangeList &snoop)
{
    cache->getAddressRanges(resp, snoop, isCpuSide);
}

int
BaseCache::CachePort::deviceBlockSize()
{
    return cache->getBlockSize();
}

bool
BaseCache::CachePort::recvTiming(Packet *pkt)
{
    if (pkt->isRequest() && blocked)
    {
        DPRINTF(Cache,"Scheduling a retry while blocked\n");
        mustSendRetry = true;
        return false;
    }
    return cache->doTimingAccess(pkt, this, isCpuSide);
}

Tick
BaseCache::CachePort::recvAtomic(Packet *pkt)
{
    return cache->doAtomicAccess(pkt, isCpuSide);
}

void
BaseCache::CachePort::recvFunctional(Packet *pkt)
{
    cache->doFunctionalAccess(pkt, isCpuSide);
}

void
BaseCache::CachePort::recvRetry()
{
    Packet *pkt;
    if (!drainList.empty()) {
        //We have some responses to drain first
        bool result = true;
        while (result && !drainList.empty()) {
            result = sendTiming(drainList.front());
            if (result)
                drainList.pop_front();
        }
    }

    if (!isCpuSide)
    {
        pkt = cache->getPacket();
        bool success = sendTiming(pkt);
        DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
                pkt->getAddr(), success ? "succesful" : "unsuccesful");
        cache->sendResult(pkt, success);
        if (success && cache->doMasterRequest())
        {
            //Still more to issue, rerequest in 1 cycle
            pkt = NULL;
            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
            reqCpu->schedule(curTick + 1);
        }
    }
    else
    {
        pkt = cache->getCoherencePacket();
        bool success = sendTiming(pkt);
        if (success && cache->doSlaveRequest())
        {
            //Still more to issue, rerequest in 1 cycle
            pkt = NULL;
            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
            reqCpu->schedule(curTick + 1);
        }

    }
    return;
}
void
BaseCache::CachePort::setBlocked()
{
    assert(!blocked);
    DPRINTF(Cache, "Cache Blocking\n");
    blocked = true;
    //Clear the retry flag
    mustSendRetry = false;
}

void
BaseCache::CachePort::clearBlocked()
{
    assert(blocked);
    DPRINTF(Cache, "Cache Unblocking\n");
    blocked = false;
    if (mustSendRetry)
    {
        DPRINTF(Cache, "Cache Sending Retry\n");
        mustSendRetry = false;
        sendRetry();
    }
}

BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort)
    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
{
    this->setFlags(AutoDelete);
    pkt = NULL;
}

BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, Packet *_pkt)
    : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), pkt(_pkt)
{
    this->setFlags(AutoDelete);
}

void
BaseCache::CacheEvent::process()
{
    if (!pkt)
    {
        if (!cachePort->isCpuSide)
        {
            //MSHR
            pkt = cachePort->cache->getPacket();
            bool success = cachePort->sendTiming(pkt);
            DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
                    pkt->getAddr(), success ? "succesful" : "unsuccesful");
            cachePort->cache->sendResult(pkt, success);
            if (success && cachePort->cache->doMasterRequest())
            {
                //Still more to issue, rerequest in 1 cycle
                pkt = NULL;
                this->schedule(curTick+1);
            }
        }
        else
        {
            //CSHR
            pkt = cachePort->cache->getCoherencePacket();
            bool success = cachePort->sendTiming(pkt);
            if (success && cachePort->cache->doSlaveRequest())
            {
                //Still more to issue, rerequest in 1 cycle
                pkt = NULL;
                this->schedule(curTick+1);
            }
        }
        return;
    }
    //Response
    //Know the packet to send
    pkt->result = Packet::Success;
    pkt->makeTimingResponse();
    if (!cachePort->drainList.empty()) {
        //Already blocked waiting for bus, just append
        cachePort->drainList.push_back(pkt);
    }
    else if (!cachePort->sendTiming(pkt)) {
        //It failed, save it to list of drain events
        cachePort->drainList.push_back(pkt);
    }
}

const char *
BaseCache::CacheEvent::description()
{
    return "timing event\n";
}

Port*
BaseCache::getPort(const std::string &if_name, int idx)
{
    if (if_name == "")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "functional")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "cpu_side")
    {
        if(cpuSidePort == NULL)
            cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
        return cpuSidePort;
    }
    else if (if_name == "mem_side")
    {
        if (memSidePort != NULL)
            panic("Already have a mem side for this cache\n");
        memSidePort = new CachePort(name() + "-mem_side_port", this, false);
        return memSidePort;
    }
    else panic("Port name %s unrecognized\n", if_name);
}

void
BaseCache::init()
{
    if (!cpuSidePort || !memSidePort)
        panic("Cache not hooked up on both sides\n");
    cpuSidePort->sendStatusChange(Port::RangeChange);
}

void
BaseCache::regStats()
{
    Request temp_req((Addr) NULL, 4, 0);
    Packet::Command temp_cmd = Packet::ReadReq;
    Packet temp_pkt(&temp_req, temp_cmd, 0);  //@todo FIx command strings so this isn't neccessary
    temp_pkt.allocate(); //Temp allocate, all need data

    using namespace Stats;

    // Hit statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        hits[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_hits")
            .desc("number of " + cstr + " hits")
            .flags(total | nozero | nonan)
            ;
    }

    demandHits
        .name(name() + ".demand_hits")
        .desc("number of demand (read+write) hits")
        .flags(total)
        ;
    demandHits = hits[Packet::ReadReq] + hits[Packet::WriteReq];

    overallHits
        .name(name() + ".overall_hits")
        .desc("number of overall hits")
        .flags(total)
        ;
    overallHits = demandHits + hits[Packet::SoftPFReq] + hits[Packet::HardPFReq]
        + hits[Packet::Writeback];

    // Miss statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        misses[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_misses")
            .desc("number of " + cstr + " misses")
            .flags(total | nozero | nonan)
            ;
    }

    demandMisses
        .name(name() + ".demand_misses")
        .desc("number of demand (read+write) misses")
        .flags(total)
        ;
    demandMisses = misses[Packet::ReadReq] + misses[Packet::WriteReq];

    overallMisses
        .name(name() + ".overall_misses")
        .desc("number of overall misses")
        .flags(total)
        ;
    overallMisses = demandMisses + misses[Packet::SoftPFReq] +
        misses[Packet::HardPFReq] + misses[Packet::Writeback];

    // Miss latency statistics
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        missLatency[access_idx]
            .init(maxThreadsPerCPU)
            .name(name() + "." + cstr + "_miss_latency")
            .desc("number of " + cstr + " miss cycles")
            .flags(total | nozero | nonan)
            ;
    }

    demandMissLatency
        .name(name() + ".demand_miss_latency")
        .desc("number of demand (read+write) miss cycles")
        .flags(total)
        ;
    demandMissLatency = missLatency[Packet::ReadReq] + missLatency[Packet::WriteReq];

    overallMissLatency
        .name(name() + ".overall_miss_latency")
        .desc("number of overall miss cycles")
        .flags(total)
        ;
    overallMissLatency = demandMissLatency + missLatency[Packet::SoftPFReq] +
        missLatency[Packet::HardPFReq];

    // access formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        accesses[access_idx]
            .name(name() + "." + cstr + "_accesses")
            .desc("number of " + cstr + " accesses(hits+misses)")
            .flags(total | nozero | nonan)
            ;

        accesses[access_idx] = hits[access_idx] + misses[access_idx];
    }

    demandAccesses
        .name(name() + ".demand_accesses")
        .desc("number of demand (read+write) accesses")
        .flags(total)
        ;
    demandAccesses = demandHits + demandMisses;

    overallAccesses
        .name(name() + ".overall_accesses")
        .desc("number of overall (read+write) accesses")
        .flags(total)
        ;
    overallAccesses = overallHits + overallMisses;

    // miss rate formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        missRate[access_idx]
            .name(name() + "." + cstr + "_miss_rate")
            .desc("miss rate for " + cstr + " accesses")
            .flags(total | nozero | nonan)
            ;

        missRate[access_idx] = misses[access_idx] / accesses[access_idx];
    }

    demandMissRate
        .name(name() + ".demand_miss_rate")
        .desc("miss rate for demand accesses")
        .flags(total)
        ;
    demandMissRate = demandMisses / demandAccesses;

    overallMissRate
        .name(name() + ".overall_miss_rate")
        .desc("miss rate for overall accesses")
        .flags(total)
        ;
    overallMissRate = overallMisses / overallAccesses;

    // miss latency formulas
    for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
        Packet::Command cmd = (Packet::Command)access_idx;
        const string &cstr = temp_pkt.cmdIdxToString(cmd);

        avgMissLatency[access_idx]
            .name(name() + "." + cstr + "_avg_miss_latency")
            .desc("average " + cstr + " miss latency")
            .flags(total | nozero | nonan)
            ;

        avgMissLatency[access_idx] =
            missLatency[access_idx] / misses[access_idx];
    }

    demandAvgMissLatency
        .name(name() + ".demand_avg_miss_latency")
        .desc("average overall miss latency")
        .flags(total)
        ;
    demandAvgMissLatency = demandMissLatency / demandMisses;

    overallAvgMissLatency
        .name(name() + ".overall_avg_miss_latency")
        .desc("average overall miss latency")
        .flags(total)
        ;
    overallAvgMissLatency = overallMissLatency / overallMisses;

    blocked_cycles.init(NUM_BLOCKED_CAUSES);
    blocked_cycles
        .name(name() + ".blocked_cycles")
        .desc("number of cycles access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    blocked_causes.init(NUM_BLOCKED_CAUSES);
    blocked_causes
        .name(name() + ".blocked")
        .desc("number of cycles access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    avg_blocked
        .name(name() + ".avg_blocked_cycles")
        .desc("average number of cycles each access was blocked")
        .subname(Blocked_NoMSHRs, "no_mshrs")
        .subname(Blocked_NoTargets, "no_targets")
        ;

    avg_blocked = blocked_cycles / blocked_causes;

    fastWrites
        .name(name() + ".fast_writes")
        .desc("number of fast writes performed")
        ;

    cacheCopies
        .name(name() + ".cache_copies")
        .desc("number of cache copies performed")
        ;

}
<|endoftext|>


<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa 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.                                     *
 *                                                                            *
 * libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_SINGLETON_MANAGER_HPP
#define CPPA_SINGLETON_MANAGER_HPP

#include <atomic>

namespace cppa {

class logging;
class scheduler;

} // namespace cppa

namespace cppa { namespace io { class middleman; } }

namespace cppa { namespace opencl { class opencl_metainfo; } }

namespace cppa { namespace detail {

class empty_tuple;
class group_manager;
class abstract_tuple;
class actor_registry;
class uniform_type_info_map;

class singleton_manager {

    singleton_manager() = delete;

 public:

    static void shutdown();

    static logging* get_logger();

    static scheduler* get_scheduler();

    static bool set_scheduler(scheduler*);

    static group_manager* get_group_manager();

    static actor_registry* get_actor_registry();

    static io::middleman* get_middleman();

    static uniform_type_info_map* get_uniform_type_info_map();

    static abstract_tuple* get_tuple_dummy();

    static empty_tuple* get_empty_tuple();

    static opencl::opencl_metainfo* get_opencl_metainfo();

 private:

    /*
     * @brief Type @p T has to provide: <tt>static T* create_singleton()</tt>,
     *        <tt>void initialize()</tt>, <tt>void destroy()</tt>,
     *        and <tt>dispose()</tt>.
     * The constructor of T shall be lightweigt, since more than one object
     * might get constructed initially.
     * <tt>dispose()</tt> is called on objects with failed CAS operation.
     * <tt>initialize()</tt> is called on objects with succeeded CAS operation.
     * <tt>destroy()</tt> is called during shutdown on initialized objects.
     *
     * Both <tt>dispose</tt> and <tt>destroy</tt> must delete the object
     * eventually.
     */
    template<typename T>
    static T* lazy_get(std::atomic<T*>& ptr) {
        T* result = ptr.load();
        while (result == nullptr) {
            auto tmp = T::create_singleton();
            if (ptr.compare_exchange_weak(result, tmp)) {
                tmp->initialize();
                result = tmp;
            }
            else tmp->dispose();
        }
        return result;
    }

    template<typename T>
    static void destroy(std::atomic<T*>& ptr) {
        for (;;) {
            auto p = ptr.load();
            if (p == nullptr) {
                return;
            }
            else if (ptr.compare_exchange_weak(p, nullptr)) {
                p->destroy();
                ptr = nullptr;
                return;
            }
        }
    }

};

} } // namespace cppa::detail

#endif // CPPA_SINGLETON_MANAGER_HPP
<commit_msg>fix singleton_manager::lazy_get<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa 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.                                     *
 *                                                                            *
 * libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_SINGLETON_MANAGER_HPP
#define CPPA_SINGLETON_MANAGER_HPP

#include <atomic>

namespace cppa {

class logging;
class scheduler;

} // namespace cppa

namespace cppa { namespace io { class middleman; } }

namespace cppa { namespace opencl { class opencl_metainfo; } }

namespace cppa { namespace detail {

class empty_tuple;
class group_manager;
class abstract_tuple;
class actor_registry;
class uniform_type_info_map;

class singleton_manager {

    singleton_manager() = delete;

 public:

    static void shutdown();

    static logging* get_logger();

    static scheduler* get_scheduler();

    static bool set_scheduler(scheduler*);

    static group_manager* get_group_manager();

    static actor_registry* get_actor_registry();

    static io::middleman* get_middleman();

    static uniform_type_info_map* get_uniform_type_info_map();

    static abstract_tuple* get_tuple_dummy();

    static empty_tuple* get_empty_tuple();

    static opencl::opencl_metainfo* get_opencl_metainfo();

 private:

    /*
     * @brief Type @p T has to provide: <tt>static T* create_singleton()</tt>,
     *        <tt>void initialize()</tt>, <tt>void destroy()</tt>,
     *        and <tt>dispose()</tt>.
     * The constructor of T shall be lightweigt, since more than one object
     * might get constructed initially.
     * <tt>dispose()</tt> is called on objects with failed CAS operation.
     * <tt>initialize()</tt> is called on objects with succeeded CAS operation.
     * <tt>destroy()</tt> is called during shutdown on initialized objects.
     *
     * Both <tt>dispose</tt> and <tt>destroy</tt> must delete the object
     * eventually.
     */
    template<typename T>
    static T* lazy_get(std::atomic<T*>& ptr) {
        T* result = ptr.load();
        while (result == nullptr) {
            auto tmp = T::create_singleton();
            // double check if singleton is still undefined
            if (ptr.load() == nullptr) {
                tmp->initialize();
                if (ptr.compare_exchange_weak(result, tmp)) {
                    result = tmp;
                }
                else tmp->destroy();
            }
            else tmp->dispose();
        }
        return result;
    }

    template<typename T>
    static void destroy(std::atomic<T*>& ptr) {
        for (;;) {
            auto p = ptr.load();
            if (p == nullptr) {
                return;
            }
            else if (ptr.compare_exchange_weak(p, nullptr)) {
                p->destroy();
                ptr = nullptr;
                return;
            }
        }
    }

};

} } // namespace cppa::detail

#endif // CPPA_SINGLETON_MANAGER_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: exc_thrower.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 09:25:52 $
 *
 *  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
 *
 ************************************************************************/

#include "osl/diagnose.h"
#include "osl/doublecheckedlocking.h"
#include "osl/mutex.hxx"
#include "uno/dispatcher.hxx"
#include "uno/mapping.hxx"
#include "cppu/XExceptionThrower.hpp"
#include "com/sun/star/uno/RuntimeException.hpp"

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

using namespace ::rtl;
using namespace ::osl;
using namespace ::cppu;
using namespace ::com::sun::star::uno;

namespace
{

//==============================================================================
struct ExceptionThrower : public uno_Interface, XExceptionThrower
{
    inline ExceptionThrower();

public:
    static ExceptionThrower * get();
    static inline Type const & getCppuType()
    {
        return ::getCppuType(
            reinterpret_cast< Reference< XExceptionThrower > const * >(0) );
    }

    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire() throw ();
    virtual void SAL_CALL release() throw ();

    // XExceptionThrower
    virtual void SAL_CALL throwException( Any const & exc ) throw (Exception);
    virtual void SAL_CALL rethrowException() throw (Exception);
};

extern "C"
{

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_acquire_release_nop( uno_Interface * )
{
}

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_dispatch(
    uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
    void * pReturn, void * pArgs [], uno_Any ** ppException )
{
    OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );

    switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >(
                const_cast< typelib_TypeDescription * >( pMemberType ) )->
            nPosition)
    {
    case 0: // queryInterace()
    {
        Type const & rType_demanded =
            *reinterpret_cast< Type const * >( pArgs[ 0 ] );
        if (rType_demanded.equals(
                ::getCppuType( reinterpret_cast<
                               Reference< XInterface > const * >(0) ) ) ||
            rType_demanded.equals( ExceptionThrower::getCppuType() ))
        {
            typelib_TypeDescription * pTD = 0;
            TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() );
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), &pUnoI, pTD, 0 );
            TYPELIB_DANGER_RELEASE( pTD );
        }
        else
        {
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), 0, 0, 0 );
        }
        *ppException = 0;
        break;
    }
    case 1: // acquire()
    case 2: // release()
        *ppException = 0;
        break;
    case 3: // throwException()
    {
        uno_Any * pAny = reinterpret_cast< uno_Any * >( pArgs[ 0 ] );
        OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
        uno_type_any_construct( *ppException, pAny->pData, pAny->pType, 0 );
        break;
    }
    default:
    {
        OSL_ASSERT( 0 );
        RuntimeException exc(
            OUSTR("not implemented!"), Reference< XInterface >() );
        uno_type_any_construct(
            *ppException, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 );
        break;
    }
    }
}

} // extern "C"

//______________________________________________________________________________
Any ExceptionThrower::queryInterface( Type const & type )
    throw (RuntimeException)
{
    if (type.equals( ::getCppuType( reinterpret_cast<
                                    Reference< XInterface > const * >(0) ) ) ||
        type.equals( ExceptionThrower::getCppuType() ))
    {
        XExceptionThrower * that = static_cast< XExceptionThrower * >( this );
        return Any( &that, type );
    }
    return Any();
}

//______________________________________________________________________________
void ExceptionThrower::acquire() throw ()
{
}
//______________________________________________________________________________
void ExceptionThrower::release() throw ()
{
}

//______________________________________________________________________________
void ExceptionThrower::throwException( Any const & exc ) throw (Exception)
{
    OSL_ENSURE( 0, "unexpected!" );
    throwException( exc );
}

//______________________________________________________________________________
void ExceptionThrower::rethrowException() throw (Exception)
{
    throw;
}

//______________________________________________________________________________
inline ExceptionThrower::ExceptionThrower()
{
    uno_Interface::acquire = ExceptionThrower_acquire_release_nop;
    uno_Interface::release = ExceptionThrower_acquire_release_nop;
    uno_Interface::pDispatcher = ExceptionThrower_dispatch;
}

//______________________________________________________________________________
ExceptionThrower * ExceptionThrower::get()
{
    ExceptionThrower * s_pThrower = 0;
    if (s_pThrower == 0)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        static ExceptionThrower s_thrower;
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
        s_pThrower = &s_thrower;
    }
    else
    {
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
    return s_pThrower;
}

} // anonymous namespace

namespace cppu
{

//==============================================================================
void SAL_CALL throwException( Any const & exc ) SAL_THROW( (Exception) )
{
    if (exc.getValueTypeClass() != TypeClass_EXCEPTION)
    {
        throw RuntimeException(
            OUSTR("no UNO exception given "
                  "(must be derived from com::sun::star::uno::Exception)!"),
            Reference< XInterface >() );
    }

    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    Reference< XExceptionThrower > xThrower;
    uno2cpp.mapInterface(
        reinterpret_cast< void ** >( &xThrower ),
        static_cast< uno_Interface * >( ExceptionThrower::get() ),
        ExceptionThrower::getCppuType() );
    OSL_ASSERT( xThrower.is() );
    xThrower->throwException( exc );
}

//==============================================================================
Any SAL_CALL getCaughtException()
{
    Mapping cpp2uno(
        OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME), OUSTR(UNO_LB_UNO) );
    if (! cpp2uno.is())
    {
        throw RuntimeException(
            OUSTR("cannot get C++ to binary UNO mapping!"),
            Reference< XInterface >() );
    }
    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    typelib_TypeDescription * pTD = 0;
    TYPELIB_DANGER_GET(
        &pTD, ExceptionThrower::getCppuType().getTypeLibType() );

    UnoInterfaceReference unoI;
    cpp2uno.mapInterface(
        reinterpret_cast< void ** >( &unoI.m_pUnoI ),
        static_cast< XExceptionThrower * >( ExceptionThrower::get() ), pTD );
    OSL_ASSERT( unoI.is() );

    typelib_TypeDescription * pMemberTD = 0;
    TYPELIB_DANGER_GET(
        &pMemberTD,
        reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )->
        ppMembers[ 1 ] /* rethrowException() */ );

    uno_Any exc_mem;
    uno_Any * exc = &exc_mem;
    unoI.dispatch( pMemberTD, 0, 0, &exc );

    TYPELIB_DANGER_RELEASE( pMemberTD );
    TYPELIB_DANGER_RELEASE( pTD );

    if (exc == 0)
    {
        throw RuntimeException(
            OUSTR("rethrowing C++ exception failed!"),
            Reference< XInterface >() );
    }

    Any ret;
    uno_any_destruct( &ret, cpp_release );
    uno_type_any_constructAndConvert(
        &ret, exc->pData, exc->pType, uno2cpp.get() );
    uno_any_destruct( exc, 0 );
    return ret;
}

}
<commit_msg>INTEGRATION: CWS sb41 (1.7.16); FILE MERGED 2005/12/16 10:48:01 sb 1.7.16.1: #i57855# Moved internal cppu.XExceptionThrower to cppuhelper.detail.XExceptionThrower to work around compilation error with MSC.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: exc_thrower.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2006-01-10 15:50:29 $
 *
 *  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
 *
 ************************************************************************/

#include "osl/diagnose.h"
#include "osl/doublecheckedlocking.h"
#include "osl/mutex.hxx"
#include "uno/dispatcher.hxx"
#include "uno/mapping.hxx"
#include "cppuhelper/detail/XExceptionThrower.hpp"
#include "com/sun/star/uno/RuntimeException.hpp"

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

using namespace ::rtl;
using namespace ::osl;
using namespace ::cppu;
using namespace ::com::sun::star::uno;

namespace
{

using cppuhelper::detail::XExceptionThrower;

//==============================================================================
struct ExceptionThrower : public uno_Interface, XExceptionThrower
{
    inline ExceptionThrower();

public:
    static ExceptionThrower * get();
    static inline Type const & getCppuType()
    {
        return ::getCppuType(
            reinterpret_cast< Reference< XExceptionThrower > const * >(0) );
    }

    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire() throw ();
    virtual void SAL_CALL release() throw ();

    // XExceptionThrower
    virtual void SAL_CALL throwException( Any const & exc ) throw (Exception);
    virtual void SAL_CALL rethrowException() throw (Exception);
};

extern "C"
{

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_acquire_release_nop( uno_Interface * )
{
}

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_dispatch(
    uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
    void * pReturn, void * pArgs [], uno_Any ** ppException )
{
    OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );

    switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >(
                const_cast< typelib_TypeDescription * >( pMemberType ) )->
            nPosition)
    {
    case 0: // queryInterace()
    {
        Type const & rType_demanded =
            *reinterpret_cast< Type const * >( pArgs[ 0 ] );
        if (rType_demanded.equals(
                ::getCppuType( reinterpret_cast<
                               Reference< XInterface > const * >(0) ) ) ||
            rType_demanded.equals( ExceptionThrower::getCppuType() ))
        {
            typelib_TypeDescription * pTD = 0;
            TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() );
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), &pUnoI, pTD, 0 );
            TYPELIB_DANGER_RELEASE( pTD );
        }
        else
        {
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), 0, 0, 0 );
        }
        *ppException = 0;
        break;
    }
    case 1: // acquire()
    case 2: // release()
        *ppException = 0;
        break;
    case 3: // throwException()
    {
        uno_Any * pAny = reinterpret_cast< uno_Any * >( pArgs[ 0 ] );
        OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
        uno_type_any_construct( *ppException, pAny->pData, pAny->pType, 0 );
        break;
    }
    default:
    {
        OSL_ASSERT( 0 );
        RuntimeException exc(
            OUSTR("not implemented!"), Reference< XInterface >() );
        uno_type_any_construct(
            *ppException, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 );
        break;
    }
    }
}

} // extern "C"

//______________________________________________________________________________
Any ExceptionThrower::queryInterface( Type const & type )
    throw (RuntimeException)
{
    if (type.equals( ::getCppuType( reinterpret_cast<
                                    Reference< XInterface > const * >(0) ) ) ||
        type.equals( ExceptionThrower::getCppuType() ))
    {
        XExceptionThrower * that = static_cast< XExceptionThrower * >( this );
        return Any( &that, type );
    }
    return Any();
}

//______________________________________________________________________________
void ExceptionThrower::acquire() throw ()
{
}
//______________________________________________________________________________
void ExceptionThrower::release() throw ()
{
}

//______________________________________________________________________________
void ExceptionThrower::throwException( Any const & exc ) throw (Exception)
{
    OSL_ENSURE( 0, "unexpected!" );
    throwException( exc );
}

//______________________________________________________________________________
void ExceptionThrower::rethrowException() throw (Exception)
{
    throw;
}

//______________________________________________________________________________
inline ExceptionThrower::ExceptionThrower()
{
    uno_Interface::acquire = ExceptionThrower_acquire_release_nop;
    uno_Interface::release = ExceptionThrower_acquire_release_nop;
    uno_Interface::pDispatcher = ExceptionThrower_dispatch;
}

//______________________________________________________________________________
ExceptionThrower * ExceptionThrower::get()
{
    ExceptionThrower * s_pThrower = 0;
    if (s_pThrower == 0)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        static ExceptionThrower s_thrower;
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
        s_pThrower = &s_thrower;
    }
    else
    {
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
    return s_pThrower;
}

} // anonymous namespace

namespace cppu
{

//==============================================================================
void SAL_CALL throwException( Any const & exc ) SAL_THROW( (Exception) )
{
    if (exc.getValueTypeClass() != TypeClass_EXCEPTION)
    {
        throw RuntimeException(
            OUSTR("no UNO exception given "
                  "(must be derived from com::sun::star::uno::Exception)!"),
            Reference< XInterface >() );
    }

    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    Reference< XExceptionThrower > xThrower;
    uno2cpp.mapInterface(
        reinterpret_cast< void ** >( &xThrower ),
        static_cast< uno_Interface * >( ExceptionThrower::get() ),
        ExceptionThrower::getCppuType() );
    OSL_ASSERT( xThrower.is() );
    xThrower->throwException( exc );
}

//==============================================================================
Any SAL_CALL getCaughtException()
{
    Mapping cpp2uno(
        OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME), OUSTR(UNO_LB_UNO) );
    if (! cpp2uno.is())
    {
        throw RuntimeException(
            OUSTR("cannot get C++ to binary UNO mapping!"),
            Reference< XInterface >() );
    }
    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    typelib_TypeDescription * pTD = 0;
    TYPELIB_DANGER_GET(
        &pTD, ExceptionThrower::getCppuType().getTypeLibType() );

    UnoInterfaceReference unoI;
    cpp2uno.mapInterface(
        reinterpret_cast< void ** >( &unoI.m_pUnoI ),
        static_cast< XExceptionThrower * >( ExceptionThrower::get() ), pTD );
    OSL_ASSERT( unoI.is() );

    typelib_TypeDescription * pMemberTD = 0;
    TYPELIB_DANGER_GET(
        &pMemberTD,
        reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )->
        ppMembers[ 1 ] /* rethrowException() */ );

    uno_Any exc_mem;
    uno_Any * exc = &exc_mem;
    unoI.dispatch( pMemberTD, 0, 0, &exc );

    TYPELIB_DANGER_RELEASE( pMemberTD );
    TYPELIB_DANGER_RELEASE( pTD );

    if (exc == 0)
    {
        throw RuntimeException(
            OUSTR("rethrowing C++ exception failed!"),
            Reference< XInterface >() );
    }

    Any ret;
    uno_any_destruct( &ret, cpp_release );
    uno_type_any_constructAndConvert(
        &ret, exc->pData, exc->pType, uno2cpp.get() );
    uno_any_destruct( exc, 0 );
    return ret;
}

}
<|endoftext|>