<commit_before>#include "cellmlmodelrepositorywindow.h"
#include "cellmlmodelrepositorywidget.h"

#include "ui_cellmlmodelrepositorywindow.h"

#include <QClipboard>
#include <QMenu>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>

#include <QJsonParser>

namespace OpenCOR {
namespace CellMLModelRepository {

CellmlModelRepositoryWindow::CellmlModelRepositoryWindow(QWidget *pParent) :
    OrganisationWidget(pParent),
    mUi(new Ui::CellmlModelRepositoryWindow)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create and add the CellML Model Repository widget

    mCellmlModelRepositoryWidget = new CellmlModelRepositoryWidget("CellmlModelRepositoryWidget",
                                                                   this);

    mUi->dockWidgetContents->layout()->addWidget(mCellmlModelRepositoryWidget);

    // We want our own context menu for the help widget (indeed, we don't want
    // the default one which has the reload menu item and not the other actions
    // that we have in our toolbar, so...)

    mCellmlModelRepositoryWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(mCellmlModelRepositoryWidget, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(customContextMenu(const QPoint &)));

    // Retrieve the list of models in the CellML Model Repository as JSON code
    // from http://50.18.64.32/workspace/rest/contents.json

    mNetworkAccessManager = new QNetworkAccessManager(this);

    // Make sure that we get told when the download of our Internet file is
    // complete

    connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply *)),
            this, SLOT(finished(QNetworkReply *)) );

    // Get the list of CellML models

    on_refreshButton_clicked();
}

CellmlModelRepositoryWindow::~CellmlModelRepositoryWindow()
{
    // Delete the UI

    delete mUi;
}

void CellmlModelRepositoryWindow::retranslateUi()
{
    // Retranslate the whole window

    mUi->retranslateUi(this);

    // Retranslate our list of models

    outputModelList(mModelList);
}

void CellmlModelRepositoryWindow::outputModelList(const QStringList &pModelList)
{
    // Output a given list of models

    mModelList = pModelList;

    QString contents = "";
    const QString leadingSpaces = "        ";

    if (mModelList.count()) {
        // We have models to list, so...

        if (mModelList.count() == 1)
            contents = tr("1 CellML model was found:")+"\n";
        else
            contents = tr("%1 CellML models were found:").arg(mModelList.count())+"\n";

        contents += leadingSpaces+"
\n";

        foreach (const QString &model, mModelList)
            contents += leadingSpaces+"
"+model+"
\n";

        contents += leadingSpaces+"
";
    } else if (mModelNames.empty()) {
        if (mErrorMsg.size()) {
            // Something went wrong while trying to retrieve the list of models,
            // so...

            QString errorMsg = mErrorMsg.left(1).toLower()+mErrorMsg.right(mErrorMsg.size()-1);
            QString dots = (errorMsg.at(errorMsg.size()-1) == '.')?"..":"...";

            contents = leadingSpaces+"Error: "+errorMsg+dots;
        } else {
            // The list is still being loaded, so...

            contents = leadingSpaces+tr("Please wait while the list of CellML models is being loaded...");
        }
    } else {
        // No model could be found, so...

        contents = leadingSpaces+tr("No CellML model matches your criteria");
    }

    // Output the list matching the search criteria, or a message telling the
    // user what went wrong, if anything

    mCellmlModelRepositoryWidget->output(contents);
}

void CellmlModelRepositoryWindow::on_nameValue_textChanged(const QString &text)
{
    // Generate a Web page that contains all the models which match our search
    // criteria

    outputModelList(mModelNames.filter(QRegExp(text)));
}

void CellmlModelRepositoryWindow::on_actionCopy_triggered()
{
    // Copy the current slection to the clipboard

    QApplication::clipboard()->setText(mCellmlModelRepositoryWidget->selectedText());
}

void CellmlModelRepositoryWindow::on_refreshButton_clicked()
{
    // Output the message telling the user that the list is being downloaded
    // Note: to clear mModelNames ensures that we get the correct message from
    //       outputModelList...

    mModelNames.clear();

    outputModelList(QStringList());

    // Disable the GUI side, so that the user doesn't get confused and ask to
    // refresh over and over again while he should just be patient

    setEnabled(false);

    // Get the list of CellML models

    mNetworkAccessManager->get(QNetworkRequest(QUrl("http://50.18.64.32/workspace/rest/contents.json")));
}

void CellmlModelRepositoryWindow::finished(QNetworkReply *pNetworkReply)
{
    // Clear some properties

    mModelNames.clear();
    mModelUrls.clear();

    mErrorMsg.clear();

    // Output the list of models, should we have retrieved it without any
    // problem

    if (pNetworkReply->error() == QNetworkReply::NoError) {
        // Parse the JSON code

        QJson::Parser jsonParser;
        bool parsingOk;

        QVariantMap res = jsonParser.parse (pNetworkReply->readAll(), &parsingOk).toMap();

        if (parsingOk) {
            // Retrieve the name of the keys

            QStringList keys;

            foreach (const QVariant &keyVariant, res["keys"].toList())
                keys << keyVariant.toString();

            // Retrieve the list of models itself

            foreach(const QVariant &modelVariant, res["values"].toList()) {
                QVariantList modelDetailsVariant = modelVariant.toList();

                mModelNames << modelDetailsVariant.at(0).toString();
                mModelUrls << modelDetailsVariant.at(1).toString();
            }
        }
    } else {
        // Something went wrong, so...

        mErrorMsg = pNetworkReply->errorString();
    }

    // Initialise the output using whatever search criteria is present

    on_nameValue_textChanged(mUi->nameValue->text());

    // Give the focus to the nameValue widget, just in case...

    mUi->nameValue->setFocus();

    // Re-enable the GUI side

    setEnabled(true);
}

void CellmlModelRepositoryWindow::customContextMenu(const QPoint &) const
{
    // Create a custom context menu for our CellML Models Repository widget

    QMenu menu;

    menu.addAction(mUi->actionCopy);

    menu.exec(QCursor::pos());
}

} }
<commit_msg>Fixed a silly overlook in the CellML Model Repository plugin (was trying to give the focus to a disabled widget!).<commit_after>#include "cellmlmodelrepositorywindow.h"
#include "cellmlmodelrepositorywidget.h"

#include "ui_cellmlmodelrepositorywindow.h"

#include <QClipboard>
#include <QMenu>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>

#include <QJsonParser>

namespace OpenCOR {
namespace CellMLModelRepository {

CellmlModelRepositoryWindow::CellmlModelRepositoryWindow(QWidget *pParent) :
    OrganisationWidget(pParent),
    mUi(new Ui::CellmlModelRepositoryWindow)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create and add the CellML Model Repository widget

    mCellmlModelRepositoryWidget = new CellmlModelRepositoryWidget("CellmlModelRepositoryWidget",
                                                                   this);

    mUi->dockWidgetContents->layout()->addWidget(mCellmlModelRepositoryWidget);

    // We want our own context menu for the help widget (indeed, we don't want
    // the default one which has the reload menu item and not the other actions
    // that we have in our toolbar, so...)

    mCellmlModelRepositoryWidget->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(mCellmlModelRepositoryWidget, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(customContextMenu(const QPoint &)));

    // Retrieve the list of models in the CellML Model Repository as JSON code
    // from http://50.18.64.32/workspace/rest/contents.json

    mNetworkAccessManager = new QNetworkAccessManager(this);

    // Make sure that we get told when the download of our Internet file is
    // complete

    connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply *)),
            this, SLOT(finished(QNetworkReply *)) );

    // Get the list of CellML models

    on_refreshButton_clicked();
}

CellmlModelRepositoryWindow::~CellmlModelRepositoryWindow()
{
    // Delete the UI

    delete mUi;
}

void CellmlModelRepositoryWindow::retranslateUi()
{
    // Retranslate the whole window

    mUi->retranslateUi(this);

    // Retranslate our list of models

    outputModelList(mModelList);
}

void CellmlModelRepositoryWindow::outputModelList(const QStringList &pModelList)
{
    // Output a given list of models

    mModelList = pModelList;

    QString contents = "";
    const QString leadingSpaces = "        ";

    if (mModelList.count()) {
        // We have models to list, so...

        if (mModelList.count() == 1)
            contents = tr("1 CellML model was found:")+"\n";
        else
            contents = tr("%1 CellML models were found:").arg(mModelList.count())+"\n";

        contents += leadingSpaces+"
\n";

        foreach (const QString &model, mModelList)
            contents += leadingSpaces+"
"+model+"
\n";

        contents += leadingSpaces+"
";
    } else if (mModelNames.empty()) {
        if (mErrorMsg.size()) {
            // Something went wrong while trying to retrieve the list of models,
            // so...

            QString errorMsg = mErrorMsg.left(1).toLower()+mErrorMsg.right(mErrorMsg.size()-1);
            QString dots = (errorMsg.at(errorMsg.size()-1) == '.')?"..":"...";

            contents = leadingSpaces+"Error: "+errorMsg+dots;
        } else {
            // The list is still being loaded, so...

            contents = leadingSpaces+tr("Please wait while the list of CellML models is being loaded...");
        }
    } else {
        // No model could be found, so...

        contents = leadingSpaces+tr("No CellML model matches your criteria");
    }

    // Output the list matching the search criteria, or a message telling the
    // user what went wrong, if anything

    mCellmlModelRepositoryWidget->output(contents);
}

void CellmlModelRepositoryWindow::on_nameValue_textChanged(const QString &text)
{
    // Generate a Web page that contains all the models which match our search
    // criteria

    outputModelList(mModelNames.filter(QRegExp(text)));
}

void CellmlModelRepositoryWindow::on_actionCopy_triggered()
{
    // Copy the current slection to the clipboard

    QApplication::clipboard()->setText(mCellmlModelRepositoryWidget->selectedText());
}

void CellmlModelRepositoryWindow::on_refreshButton_clicked()
{
    // Output the message telling the user that the list is being downloaded
    // Note: to clear mModelNames ensures that we get the correct message from
    //       outputModelList...

    mModelNames.clear();

    outputModelList(QStringList());

    // Disable the GUI side, so that the user doesn't get confused and ask to
    // refresh over and over again while he should just be patient

    setEnabled(false);

    // Get the list of CellML models

    mNetworkAccessManager->get(QNetworkRequest(QUrl("http://50.18.64.32/workspace/rest/contents.json")));
}

void CellmlModelRepositoryWindow::finished(QNetworkReply *pNetworkReply)
{
    // Clear some properties

    mModelNames.clear();
    mModelUrls.clear();

    mErrorMsg.clear();

    // Output the list of models, should we have retrieved it without any
    // problem

    if (pNetworkReply->error() == QNetworkReply::NoError) {
        // Parse the JSON code

        QJson::Parser jsonParser;
        bool parsingOk;

        QVariantMap res = jsonParser.parse (pNetworkReply->readAll(), &parsingOk).toMap();

        if (parsingOk) {
            // Retrieve the name of the keys

            QStringList keys;

            foreach (const QVariant &keyVariant, res["keys"].toList())
                keys << keyVariant.toString();

            // Retrieve the list of models itself

            foreach(const QVariant &modelVariant, res["values"].toList()) {
                QVariantList modelDetailsVariant = modelVariant.toList();

                mModelNames << modelDetailsVariant.at(0).toString();
                mModelUrls << modelDetailsVariant.at(1).toString();
            }
        }
    } else {
        // Something went wrong, so...

        mErrorMsg = pNetworkReply->errorString();
    }

    // Initialise the output using whatever search criteria is present

    on_nameValue_textChanged(mUi->nameValue->text());

    // Re-enable the GUI side

    setEnabled(true);

    // Give the focus to the nameValue widget, just in case...

    mUi->nameValue->setFocus();
}

void CellmlModelRepositoryWindow::customContextMenu(const QPoint &) const
{
    // Create a custom context menu for our CellML Models Repository widget

    QMenu menu;

    menu.addAction(mUi->actionCopy);

    menu.exec(QCursor::pos());
}

} }
<|endoftext|>


<commit_before>#include "Algo.h"
#include <iostream>
#include <algorithm>
#include <time.h>
#include <math.h>

using namespace std;

void Algo::fillMap(int map[], int size)
{
	srand(time(NULL));
	int MapSize = size * size;
	for (int x = 0; x < MapSize; x++)
	{
			map[x] = x % 4;
	}
}<commit_msg>algo fix<commit_after>#include "Algo.h"
#include <iostream>
#include <algorithm>
#include <time.h>
#include <math.h>

using namespace std;

void Algo::fillMap(int map[], int size)
{
	srand(time(NULL));
	int MapSize = size * size;
	int nbType[4] = { MapSize / 4, MapSize / 4, MapSize / 4, MapSize / 4 };
	for (int x = 0; x < MapSize; x++)
	{
		int tile = rand() % 4;
		while (nbType[tile] == 0) {
			tile = rand() % 4;
		}
		nbType[tile]--;
		map[x] = tile;
	}
}<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

#include "Backend.h"

JITObjTypeSpecFldInfo::JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data) :
    m_data(*data)
{
    CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(JITObjTypeSpecFldInfo));
}

bool
JITObjTypeSpecFldInfo::UsesAuxSlot() const
{
    return GetFlags().usesAuxSlot;
}

bool
JITObjTypeSpecFldInfo::UsesAccessor() const
{
    return GetFlags().usesAccessor;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
{
    return GetFlags().isRootObjectNonConfigurableFieldLoad;
}

bool
JITObjTypeSpecFldInfo::HasEquivalentTypeSet() const
{
    return m_data.typeSet != nullptr;
}

bool
JITObjTypeSpecFldInfo::DoesntHaveEquivalence() const
{
    return GetFlags().doesntHaveEquivalence;
}

bool
JITObjTypeSpecFldInfo::IsPoly() const
{
    return GetFlags().isPolymorphic;
}

bool
JITObjTypeSpecFldInfo::IsMono() const
{
    return !IsPoly();
}

bool
JITObjTypeSpecFldInfo::IsBuiltIn() const
{
    return GetFlags().isBuiltIn;
}

bool
JITObjTypeSpecFldInfo::IsLoadedFromProto() const
{
    return GetFlags().isLoadedFromProto;
}

bool
JITObjTypeSpecFldInfo::HasFixedValue() const
{
    return GetFlags().hasFixedValue;
}

bool
JITObjTypeSpecFldInfo::IsBeingStored() const
{
    return GetFlags().isBeingStored;
}

bool
JITObjTypeSpecFldInfo::IsBeingAdded() const
{
    return GetFlags().isBeingAdded;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
{
    return GetFlags().isRootObjectNonConfigurableField;
}

bool
JITObjTypeSpecFldInfo::HasInitialType() const
{
    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
}

bool
JITObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
{
    return IsMono();
}

bool
JITObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
{
    return IsPoly();
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId() const
{
    Assert(m_data.typeId != Js::TypeIds_Limit);
    return (Js::TypeId)m_data.typeId;
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId(uint i) const
{
    Assert(IsPoly());
    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type->typeId;
}

Js::PropertyId
JITObjTypeSpecFldInfo::GetPropertyId() const
{
    return (Js::PropertyId)m_data.propertyId;
}

uint16
JITObjTypeSpecFldInfo::GetSlotIndex() const
{
    return m_data.slotIndex;
}

uint16
JITObjTypeSpecFldInfo::GetFixedFieldCount() const
{
    return m_data.fixedFieldCount;
}

uint
JITObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
{
    return m_data.id;
}

intptr_t
JITObjTypeSpecFldInfo::GetProtoObject() const
{
    return m_data.protoObjectAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValue(uint i) const
{
    Assert(IsPoly());
    return m_data.fixedFieldInfoArray[i].fieldValue;
}

intptr_t
JITObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
{
    return m_data.propertyGuardValueAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
{
    Assert(HasFixedValue() && GetFixedFieldCount() == 1);

    return m_data.fixedFieldInfoArray[0].fieldValue;
}

JITTimeConstructorCache *
JITObjTypeSpecFldInfo::GetCtorCache() const
{
    return (JITTimeConstructorCache*)m_data.ctorCache;
}

Js::EquivalentTypeSet *
JITObjTypeSpecFldInfo::GetEquivalentTypeSet() const
{
    return (Js::EquivalentTypeSet *)m_data.typeSet;
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType() const
{
    Assert(IsMono());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[0].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType(uint i) const
{
    Assert(IsPoly());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[i].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetInitialType() const
{
    return JITTypeHolder((JITType *)m_data.initialType);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetFirstEquivalentType() const
{
    Assert(HasEquivalentTypeSet());
    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
}

void
JITObjTypeSpecFldInfo::SetIsBeingStored(bool value)
{
    ((Js::ObjTypeSpecFldInfoFlags*)&m_data.flags)->isBeingStored = value;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
{
    Assert(HasFixedValue());
    Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
    Assert(m_data.fixedFieldInfoArray);
    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[0];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
{
    Assert(HasFixedValue());
    Assert(IsPoly());
    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[i];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldInfoArray()
{
    return (JITTimeFixedField*)m_data.fixedFieldInfoArray;
}

/* static */
void
JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(
    __in ArenaAllocator * alloc,
    __in Js::ObjTypeSpecFldInfo ** objTypeSpecInfo,
    __in uint arrayLength,
    _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData)
{
    for (uint i = 0; i < arrayLength; ++i)
    {
        if (objTypeSpecInfo[i] == nullptr)
        {
            continue;
        }
        jitData[i].inUse = TRUE;
        if (objTypeSpecInfo[i]->IsLoadedFromProto())
        {
            jitData[i].protoObjectAddr = (intptr_t)objTypeSpecInfo[i]->GetProtoObject();
        }
        jitData[i].propertyGuardValueAddr = (intptr_t)objTypeSpecInfo[i]->GetPropertyGuard()->GetAddressOfValue();
        jitData[i].propertyId = objTypeSpecInfo[i]->GetPropertyId();
        jitData[i].typeId = objTypeSpecInfo[i]->GetTypeId();
        jitData[i].id = objTypeSpecInfo[i]->GetObjTypeSpecFldId();
        jitData[i].flags = objTypeSpecInfo[i]->GetFlags();
        jitData[i].slotIndex = objTypeSpecInfo[i]->GetSlotIndex();
        jitData[i].fixedFieldCount = objTypeSpecInfo[i]->GetFixedFieldCount();

        if (objTypeSpecInfo[i]->HasInitialType())
        {
            jitData[i].initialType = AnewStructZ(alloc, TypeIDL);
            JITType::BuildFromJsType(objTypeSpecInfo[i]->GetInitialType(), (JITType*)jitData[i].initialType);
        }

        if (objTypeSpecInfo[i]->GetCtorCache() != nullptr)
        {
            jitData[i].ctorCache = objTypeSpecInfo[i]->GetCtorCache()->GetData();
        }

        CompileAssert(sizeof(Js::EquivalentTypeSet) == sizeof(EquivalentTypeSetIDL));
        Js::EquivalentTypeSet * equivTypeSet = objTypeSpecInfo[i]->GetEquivalentTypeSet();
        if (equivTypeSet != nullptr)
        {
            jitData[i].typeSet = (EquivalentTypeSetIDL*)equivTypeSet;
        }

        jitData[i].fixedFieldInfoArraySize = jitData[i].fixedFieldCount;
        if (jitData[i].fixedFieldInfoArraySize == 0)
        {
            jitData[i].fixedFieldInfoArraySize = 1;
        }
        jitData[i].fixedFieldInfoArray = AnewArrayZ(alloc, FixedFieldIDL, jitData[i].fixedFieldInfoArraySize);
        Js::FixedFieldInfo * ffInfo = objTypeSpecInfo[i]->GetFixedFieldInfoArray();
        for (uint16 j = 0; j < jitData[i].fixedFieldInfoArraySize; ++j)
        {
            jitData[i].fixedFieldInfoArray[j].fieldValue = (intptr_t)ffInfo[j].fieldValue;
            jitData[i].fixedFieldInfoArray[j].nextHasSameFixedField = ffInfo[j].nextHasSameFixedField;
            if (ffInfo[j].fieldValue != nullptr && Js::JavascriptFunction::Is(ffInfo[j].fieldValue))
            {
                Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(ffInfo[j].fieldValue);
                jitData[i].fixedFieldInfoArray[j].valueType = ValueType::FromObject(funcObj).GetRawData();
                jitData[i].fixedFieldInfoArray[j].funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
                jitData[i].fixedFieldInfoArray[j].localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
                if (Js::ScriptFunction::Is(ffInfo[j].fieldValue))
                {
                    jitData[i].fixedFieldInfoArray[j].environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
                }
            }
            if (ffInfo[j].type != nullptr)
            {
                jitData[i].fixedFieldInfoArray[j].type = AnewStructZ(alloc, TypeIDL);
                // TODO: OOP JIT, maybe type should be out of line? might not save anything on x64 though
                JITType::BuildFromJsType(ffInfo[j].type, (JITType*)jitData[i].fixedFieldInfoArray[j].type);
            }
        }
    }
}

Js::ObjTypeSpecFldInfoFlags
JITObjTypeSpecFldInfo::GetFlags() const
{
    return (Js::ObjTypeSpecFldInfoFlags)m_data.flags;
}
<commit_msg>fix oopjit bug with fixed ctors<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

#include "Backend.h"

JITObjTypeSpecFldInfo::JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data) :
    m_data(*data)
{
    CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(JITObjTypeSpecFldInfo));
}

bool
JITObjTypeSpecFldInfo::UsesAuxSlot() const
{
    return GetFlags().usesAuxSlot;
}

bool
JITObjTypeSpecFldInfo::UsesAccessor() const
{
    return GetFlags().usesAccessor;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
{
    return GetFlags().isRootObjectNonConfigurableFieldLoad;
}

bool
JITObjTypeSpecFldInfo::HasEquivalentTypeSet() const
{
    return m_data.typeSet != nullptr;
}

bool
JITObjTypeSpecFldInfo::DoesntHaveEquivalence() const
{
    return GetFlags().doesntHaveEquivalence;
}

bool
JITObjTypeSpecFldInfo::IsPoly() const
{
    return GetFlags().isPolymorphic;
}

bool
JITObjTypeSpecFldInfo::IsMono() const
{
    return !IsPoly();
}

bool
JITObjTypeSpecFldInfo::IsBuiltIn() const
{
    return GetFlags().isBuiltIn;
}

bool
JITObjTypeSpecFldInfo::IsLoadedFromProto() const
{
    return GetFlags().isLoadedFromProto;
}

bool
JITObjTypeSpecFldInfo::HasFixedValue() const
{
    return GetFlags().hasFixedValue;
}

bool
JITObjTypeSpecFldInfo::IsBeingStored() const
{
    return GetFlags().isBeingStored;
}

bool
JITObjTypeSpecFldInfo::IsBeingAdded() const
{
    return GetFlags().isBeingAdded;
}

bool
JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
{
    return GetFlags().isRootObjectNonConfigurableField;
}

bool
JITObjTypeSpecFldInfo::HasInitialType() const
{
    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
}

bool
JITObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
{
    return IsMono();
}

bool
JITObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
{
    return IsPoly();
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId() const
{
    Assert(m_data.typeId != Js::TypeIds_Limit);
    return (Js::TypeId)m_data.typeId;
}

Js::TypeId
JITObjTypeSpecFldInfo::GetTypeId(uint i) const
{
    Assert(IsPoly());
    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type->typeId;
}

Js::PropertyId
JITObjTypeSpecFldInfo::GetPropertyId() const
{
    return (Js::PropertyId)m_data.propertyId;
}

uint16
JITObjTypeSpecFldInfo::GetSlotIndex() const
{
    return m_data.slotIndex;
}

uint16
JITObjTypeSpecFldInfo::GetFixedFieldCount() const
{
    return m_data.fixedFieldCount;
}

uint
JITObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
{
    return m_data.id;
}

intptr_t
JITObjTypeSpecFldInfo::GetProtoObject() const
{
    return m_data.protoObjectAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValue(uint i) const
{
    Assert(IsPoly());
    return m_data.fixedFieldInfoArray[i].fieldValue;
}

intptr_t
JITObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
{
    return m_data.propertyGuardValueAddr;
}

intptr_t
JITObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
{
    Assert(HasFixedValue() && GetFixedFieldCount() == 1);

    return m_data.fixedFieldInfoArray[0].fieldValue;
}

JITTimeConstructorCache *
JITObjTypeSpecFldInfo::GetCtorCache() const
{
    return (JITTimeConstructorCache*)m_data.ctorCache;
}

Js::EquivalentTypeSet *
JITObjTypeSpecFldInfo::GetEquivalentTypeSet() const
{
    return (Js::EquivalentTypeSet *)m_data.typeSet;
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType() const
{
    Assert(IsMono());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[0].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetType(uint i) const
{
    Assert(IsPoly());
    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[i].type);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetInitialType() const
{
    return JITTypeHolder((JITType *)m_data.initialType);
}

JITTypeHolder
JITObjTypeSpecFldInfo::GetFirstEquivalentType() const
{
    Assert(HasEquivalentTypeSet());
    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
}

void
JITObjTypeSpecFldInfo::SetIsBeingStored(bool value)
{
    ((Js::ObjTypeSpecFldInfoFlags*)&m_data.flags)->isBeingStored = value;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
{
    Assert(HasFixedValue());
    Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
    Assert(m_data.fixedFieldInfoArray);
    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[0];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
{
    Assert(HasFixedValue());
    Assert(IsPoly());
    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
    {
        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[i];
    }
    return nullptr;
}

JITTimeFixedField *
JITObjTypeSpecFldInfo::GetFixedFieldInfoArray()
{
    return (JITTimeFixedField*)m_data.fixedFieldInfoArray;
}

/* static */
void
JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(
    __in ArenaAllocator * alloc,
    __in Js::ObjTypeSpecFldInfo ** objTypeSpecInfo,
    __in uint arrayLength,
    _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData)
{
    for (uint i = 0; i < arrayLength; ++i)
    {
        if (objTypeSpecInfo[i] == nullptr)
        {
            continue;
        }
        jitData[i].inUse = TRUE;
        if (objTypeSpecInfo[i]->IsLoadedFromProto())
        {
            jitData[i].protoObjectAddr = (intptr_t)objTypeSpecInfo[i]->GetProtoObject();
        }
        jitData[i].propertyGuardValueAddr = (intptr_t)objTypeSpecInfo[i]->GetPropertyGuard()->GetAddressOfValue();
        jitData[i].propertyId = objTypeSpecInfo[i]->GetPropertyId();
        jitData[i].typeId = objTypeSpecInfo[i]->GetTypeId();
        jitData[i].id = objTypeSpecInfo[i]->GetObjTypeSpecFldId();
        jitData[i].flags = objTypeSpecInfo[i]->GetFlags();
        jitData[i].slotIndex = objTypeSpecInfo[i]->GetSlotIndex();
        jitData[i].fixedFieldCount = objTypeSpecInfo[i]->GetFixedFieldCount();

        if (objTypeSpecInfo[i]->HasInitialType())
        {
            jitData[i].initialType = AnewStructZ(alloc, TypeIDL);
            JITType::BuildFromJsType(objTypeSpecInfo[i]->GetInitialType(), (JITType*)jitData[i].initialType);
        }

        if (objTypeSpecInfo[i]->GetCtorCache() != nullptr)
        {
            jitData[i].ctorCache = objTypeSpecInfo[i]->GetCtorCache()->GetData();
        }

        CompileAssert(sizeof(Js::EquivalentTypeSet) == sizeof(EquivalentTypeSetIDL));
        Js::EquivalentTypeSet * equivTypeSet = objTypeSpecInfo[i]->GetEquivalentTypeSet();
        if (equivTypeSet != nullptr)
        {
            jitData[i].typeSet = (EquivalentTypeSetIDL*)equivTypeSet;
        }

        jitData[i].fixedFieldInfoArraySize = jitData[i].fixedFieldCount;
        if (jitData[i].fixedFieldInfoArraySize == 0)
        {
            jitData[i].fixedFieldInfoArraySize = 1;
        }
        jitData[i].fixedFieldInfoArray = AnewArrayZ(alloc, FixedFieldIDL, jitData[i].fixedFieldInfoArraySize);
        Js::FixedFieldInfo * ffInfo = objTypeSpecInfo[i]->GetFixedFieldInfoArray();
        for (uint16 j = 0; j < jitData[i].fixedFieldInfoArraySize; ++j)
        {
            jitData[i].fixedFieldInfoArray[j].fieldValue = (intptr_t)ffInfo[j].fieldValue;
            jitData[i].fixedFieldInfoArray[j].nextHasSameFixedField = ffInfo[j].nextHasSameFixedField;
            if (ffInfo[j].fieldValue != nullptr && Js::JavascriptFunction::Is(ffInfo[j].fieldValue))
            {
                Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(ffInfo[j].fieldValue);
                jitData[i].fixedFieldInfoArray[j].valueType = ValueType::FromObject(funcObj).GetRawData();
                jitData[i].fixedFieldInfoArray[j].funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
                jitData[i].fixedFieldInfoArray[j].isClassCtor = funcObj->GetFunctionInfo()->IsConstructor();
                jitData[i].fixedFieldInfoArray[j].localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
                if (Js::ScriptFunction::Is(ffInfo[j].fieldValue))
                {
                    jitData[i].fixedFieldInfoArray[j].environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
                }
            }
            if (ffInfo[j].type != nullptr)
            {
                jitData[i].fixedFieldInfoArray[j].type = AnewStructZ(alloc, TypeIDL);
                // TODO: OOP JIT, maybe type should be out of line? might not save anything on x64 though
                JITType::BuildFromJsType(ffInfo[j].type, (JITType*)jitData[i].fixedFieldInfoArray[j].type);
            }
        }
    }
}

Js::ObjTypeSpecFldInfoFlags
JITObjTypeSpecFldInfo::GetFlags() const
{
    return (Js::ObjTypeSpecFldInfoFlags)m_data.flags;
}
<|endoftext|>


<commit_before>// bslstl_hashtable.cpp                                               -*-C++-*-
#include <bslstl_hashtable.h>

#include <bsls_ident.h>
BSLS_IDENT("$Id$ $CSID$")

#include <bslstl_equalto.h>            // for testing only
#include <bslstl_hash.h>               // for testing only
#include <bslstl_hashtableiterator.h>  // for testing only
#include <bslstl_iterator.h>           // for testing only
#include <bslstl_stdexceptutil.h>

#include <bslma_mallocfreeallocator.h>

#include <bsls_nativestd.h>

#include <algorithm>         // 'lower_bound'
#include <limits>

namespace BloombergLP
{
namespace bslstl
{

                    // --------------------------
                    // class HashTable_ImpDetails
                    // --------------------------

bslalg::HashTableBucket *HashTable_ImpDetails::defaultBucketAddress()
{
    static bslalg::HashTableBucket s_bucket = {0 , 0};
                                                  // Aggregate initialization
                                                  // of a POD should be thread-
                                                  // safe static initialization

    // These two tests should not be necessary, but will catch corruption in
    // components that try to write to the shared bucket.

    BSLS_ASSERT_SAFE(!s_bucket.first());
    BSLS_ASSERT_SAFE(!s_bucket.last());

    return &s_bucket;
}

size_t HashTable_ImpDetails::growBucketsForLoadFactor(size_t *capacity,
                                                      size_t  minElements,
                                                      size_t  requestedBuckets,
                                                      double  maxLoadFactor)
{
    BSLS_ASSERT_SAFE(  0 != capacity);
    BSLS_ASSERT_SAFE(  0  < minElements);
    BSLS_ASSERT_SAFE(  0  < requestedBuckets);
    BSLS_ASSERT_SAFE(0.0  < maxLoadFactor);

    static const size_t MAX_SIZE_T = native_std::numeric_limits<size_t>::max();
    static const double MAX_AS_DBL = static_cast<double>(MAX_SIZE_T);

    struct Impl {
        // This local utility class provides a couple of methods for converting
        // 'double' values to 'size_t' values, applying different policies in
        // event of an overflow.  This clarifies the main logic of the function
        // rather than placing this logic inline a number of times.

        // CLASS METHODS
        static size_t roundToMax(double d)
            // Return the integer value corresponding to the specified 'd', or
            // the highest unsigned value representable by 'size_t' if 'd' is
            // larger.  The behavior is undefined unless '0.0 <= d'.
        {
            BSLS_ASSERT_SAFE(0.0 <= d);

            return d < MAX_AS_DBL
                 ? static_cast<size_t>(d)
                 : MAX_SIZE_T;
        }

        static size_t throwIfOverMax(double d)
            // Throw a 'std::length_error' exception if the specified 'd' is
            // larger than the highest unsigned value representable by
            // 'size_t'.  Return the integer value corresponding to 'd',
            // rounding down.  The behavior is undefined unless '0.0 <= d'.
        {
            BSLS_ASSERT_SAFE(0.0 <= d);

            if (d > MAX_AS_DBL) {
                StdExceptUtil::throwLengthError(
                                           "The number of buckets overflows.");
            }

            return static_cast<size_t>(d);
        }
    };

    // This check is why 'minElements' must be at least one - so that we do not
    // allocate a number of buckets that cannot hold at least one element, and
    // then throw the unexpected 'logic_error' on the first 'insert'.  We make
    // it a pre-condition of the function, as some callers have contextual
    // knowledge that the argument must be non-zero, and so avoid a redundant
    // 'min' call.  The 'static_cast<double>' addresses warnings on 64-bit
    // systems.  The truncation that occurs in such cases does not impact the
    // final result, so we do not need any deeper analysis in such cases.

    size_t result = native_std::max(
       requestedBuckets,
       Impl::throwIfOverMax(static_cast<double>(minElements) / maxLoadFactor));

    result = nextPrime(result);  // throws if too large

    double newCapacity = static_cast<double>(result) * maxLoadFactor;

    while (minElements > newCapacity ) {
        result  = nextPrime(2 * result);  // throws if too large
        newCapacity = static_cast<double>(result) * maxLoadFactor;
    }

    *capacity = Impl::roundToMax(newCapacity);
    return result;
}

bslma::Allocator *HashTable_ImpDetails::incidentalAllocator()
{
    // Note that this function is deliberately defined out-of-line in the .cpp
    // file, rather than as an inline function in the .h file, due to problems
    // raised by #including <bslma_mallocfree.h> directly in the header for
    // (much) higher level code that, for historical reasons, defines 'malloc'
    // and 'free' as macros in order to remap them to shared memory.  The
    // simplest solution is to simply isolate our use of the malloc-free
    // allocator to this .cpp file, which is built without those strange
    // configuration macros installed.

    return &bslma::MallocFreeAllocator::singleton();
}

size_t HashTable_ImpDetails::nextPrime(size_t n)
{
    // An abbreviated list of prime numbers in the domain of 32-bit unsigned
    // integers.  Essentially, a subset where each successive element is the
    // next prime after doubling.  Note that at least one of these numbers was
    // mis-computed and undershoots, messing up the doubling pattern, not
    // critical while the code remains proof-of-concept code.

    static const size_t s_primes[] = { 2, 5, 13, 29, 61,
        127, 257, 521, 1049, 2099, 4201, 8419, 16843, 33703, 67409, 134837,
        269513, 539039, 1078081, 2156171, 5312353, 10624709, 21249443,
        42498893, 84997793, 169995589, 339991181, 679982363, 1359964751,
        2719929503u

    };
    static const size_t s_nPrimes = sizeof(s_primes)/sizeof(s_primes[0]);
    static const size_t *const s_beginPrimes = s_primes;
    static const size_t *const s_endPrimes   = s_primes + s_nPrimes;

    const size_t *result = native_std::lower_bound(s_beginPrimes,
                                                   s_endPrimes,
                                                   n);
    if (s_endPrimes == result) {
        StdExceptUtil::throwLengthError("HashTable ran out of prime numbers.");
    }

    return *result;
}

}  // close package namespace
}  // close enterprise namespace
// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>Adopt commit 376e36a from master: Merge pull request #688 from hrosen4/hashtable-static-init-drqs-58680630<commit_after>// bslstl_hashtable.cpp                                               -*-C++-*-
#include <bslstl_hashtable.h>

#include <bsls_ident.h>
BSLS_IDENT("$Id$ $CSID$")

#include <bslstl_equalto.h>            // for testing only
#include <bslstl_hash.h>               // for testing only
#include <bslstl_hashtableiterator.h>  // for testing only
#include <bslstl_iterator.h>           // for testing only
#include <bslstl_stdexceptutil.h>

#include <bslma_mallocfreeallocator.h>

#include <bsls_nativestd.h>

#include <algorithm>         // 'lower_bound'
#include <limits>

namespace BloombergLP
{
namespace bslstl
{

                    // --------------------------
                    // class HashTable_ImpDetails
                    // --------------------------

bslalg::HashTableBucket *HashTable_ImpDetails::defaultBucketAddress()
{
    static bslalg::HashTableBucket s_bucket = {0 , 0};
                                                  // Aggregate initialization
                                                  // of a POD should be thread-
                                                  // safe static initialization

    // These two tests should not be necessary, but will catch corruption in
    // components that try to write to the shared bucket.

    BSLS_ASSERT_SAFE(!s_bucket.first());
    BSLS_ASSERT_SAFE(!s_bucket.last());

    return &s_bucket;
}

size_t HashTable_ImpDetails::growBucketsForLoadFactor(size_t *capacity,
                                                      size_t  minElements,
                                                      size_t  requestedBuckets,
                                                      double  maxLoadFactor)
{
    BSLS_ASSERT_SAFE(  0 != capacity);
    BSLS_ASSERT_SAFE(  0  < minElements);
    BSLS_ASSERT_SAFE(  0  < requestedBuckets);
    BSLS_ASSERT_SAFE(0.0  < maxLoadFactor);

    const size_t MAX_SIZE_T = native_std::numeric_limits<size_t>::max();
    const double MAX_AS_DBL = static_cast<double>(MAX_SIZE_T);

    // This check is why 'minElements' must be at least one - so that we do not
    // allocate a number of buckets that cannot hold at least one element, and
    // then throw the unexpected 'logic_error' on the first 'insert'.  We make
    // it a pre-condition of the function, as some callers have contextual
    // knowledge that the argument must be non-zero, and so avoid a redundant
    // 'min' call.  The 'static_cast<double>' addresses warnings on 64-bit
    // systems.  The truncation that occurs in such cases does not impact the
    // final result, so we do not need any deeper analysis in such cases.

    double d = static_cast<double>(minElements) / maxLoadFactor;
    if (d > MAX_AS_DBL) {
        // Throw a 'std::length_error' exception if 'd' is larger than the
        // highest unsigned value representable by 'size_t'.
        StdExceptUtil::throwLengthError("The number of buckets overflows.");
    }
    for (size_t result =
             native_std::max(requestedBuckets, static_cast<size_t>(d));
         ;
         result *= 2) {
        result = nextPrime(result);  // throws if too large
        double newCapacity = static_cast<double>(result) * maxLoadFactor;
        if (minElements <= newCapacity) {
            // Set '*capacity' to the integer value corresponding to
            // 'newCapacity', or the highest unsigned value representable by
            // 'size_t' if 'newCapacity' is larger.
            *capacity = newCapacity < MAX_AS_DBL
                            ? static_cast<size_t>(newCapacity)
                            : MAX_SIZE_T;
            return result;                                            // RETURN
        }
    }
}

bslma::Allocator *HashTable_ImpDetails::incidentalAllocator()
{
    // Note that this function is deliberately defined out-of-line in the .cpp
    // file, rather than as an inline function in the .h file, due to problems
    // raised by #including <bslma_mallocfree.h> directly in the header for
    // (much) higher level code that, for historical reasons, defines 'malloc'
    // and 'free' as macros in order to remap them to shared memory.  The
    // simplest solution is to simply isolate our use of the malloc-free
    // allocator to this .cpp file, which is built without those strange
    // configuration macros installed.

    return &bslma::MallocFreeAllocator::singleton();
}

size_t HashTable_ImpDetails::nextPrime(size_t n)
{
    // An abbreviated list of prime numbers in the domain of 32-bit unsigned
    // integers.  Essentially, a subset where each successive element is the
    // next prime after doubling.  Note that at least one of these numbers was
    // mis-computed and undershoots, messing up the doubling pattern, not
    // critical while the code remains proof-of-concept code.

    static const size_t s_primes[] = { 2, 5, 13, 29, 61,
        127, 257, 521, 1049, 2099, 4201, 8419, 16843, 33703, 67409, 134837,
        269513, 539039, 1078081, 2156171, 5312353, 10624709, 21249443,
        42498893, 84997793, 169995589, 339991181, 679982363, 1359964751,
        2719929503u

    };
    static const size_t s_nPrimes = sizeof(s_primes)/sizeof(s_primes[0]);
    static const size_t *const s_beginPrimes = s_primes;
    static const size_t *const s_endPrimes   = s_primes + s_nPrimes;

    const size_t *result = native_std::lower_bound(s_beginPrimes,
                                                   s_endPrimes,
                                                   n);
    if (s_endPrimes == result) {
        StdExceptUtil::throwLengthError("HashTable ran out of prime numbers.");
    }

    return *result;
}

}  // close package namespace
}  // close enterprise namespace
// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>/*
 *  Detector.cpp
 *  zxing
 *
 *  Created by Christian Brunschen on 14/05/2008.
 *  Copyright 2008 ZXing authors All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/qrcode/detector/Detector.h>
#include <zxing/qrcode/detector/FinderPatternFinder.h>
#include <zxing/qrcode/detector/FinderPattern.h>
#include <zxing/qrcode/detector/AlignmentPattern.h>
#include <zxing/qrcode/detector/AlignmentPatternFinder.h>
#include <zxing/qrcode/Version.h>
#include <zxing/common/GridSampler.h>
#include <zxing/DecodeHints.h>
#include <cmath>
#include <sstream>
#include <cstdlib>

namespace zxing {
namespace qrcode {

using namespace std;

Detector::Detector(Ref<BitMatrix> image) :
    image_(image) {
}

Ref<BitMatrix> Detector::getImage() {
   return image_;
}

Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
  callback_ = hints.getResultPointCallback();
  FinderPatternFinder finder(image_, hints.getResultPointCallback());
  Ref<FinderPatternInfo> info(finder.find(hints));

  Ref<FinderPattern> topLeft(info->getTopLeft());
  Ref<FinderPattern> topRight(info->getTopRight());
  Ref<FinderPattern> bottomLeft(info->getBottomLeft());

  float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);
  if (moduleSize < 1.0f) {
    throw zxing::ReaderException("bad module size");
  }
  int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
  Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension);
  int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7;

  Ref<AlignmentPattern> alignmentPattern;
  // Anything above version 1 has an alignment pattern
  if (provisionalVersion->getAlignmentPatternCenters().size() > 0) {

    // Guess where a "bottom right" finder pattern would have been
    float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX();
    float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY();

    // Estimate that alignment pattern is closer by 3 modules
    // from "bottom right" to known top left location
    float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters;
    int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX()));
    int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY()));

    // Kind of arbitrary -- expand search radius before giving up
    for (int i = 4; i <= 16; i <<= 1) {
      try {
        alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i);
        break;
      } catch (zxing::ReaderException re) {
        // try next round
      }
    }
    if (alignmentPattern == 0) {
      // Try anyway
    }

  }

  Ref<PerspectiveTransform> transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
  Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
  std::vector<Ref<ResultPoint> > points(alignmentPattern == 0 ? 3 : 4);
  points[0].reset(bottomLeft);
  points[1].reset(topLeft);
  points[2].reset(topRight);
  if (alignmentPattern != 0) {
    points[3].reset(alignmentPattern);
  }

  Ref<DetectorResult> result(new DetectorResult(bits, points, transform));
  return result;
}

Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
    ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {

  float dimMinusThree = (float)dimension - 3.5f;
  float bottomRightX;
  float bottomRightY;
  float sourceBottomRightX;
  float sourceBottomRightY;
  if (alignmentPattern != 0) {
    bottomRightX = alignmentPattern->getX();
    bottomRightY = alignmentPattern->getY();
    sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
  } else {
    // Don't have an alignment pattern, just make up the bottom-right point
    bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX();
    bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY();
    sourceBottomRightX = sourceBottomRightY = dimMinusThree;
  }

  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX,
                                      sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(),
                                      topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY()));

  return transform;
}

Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
  GridSampler &sampler = GridSampler::getInstance();
  return sampler.sampleGrid(image, dimension, transform);
}

int Detector::computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,
                               float moduleSize) {
  int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f);
  int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f);
  int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
  switch (dimension & 0x03) { // mod 4
  case 0:
    dimension++;
    break;
    // 1? do nothing
  case 2:
    dimension--;
    break;
  case 3:
    ostringstream s;
    s << "Bad dimension: " << dimension;
    throw zxing::ReaderException(s.str().c_str());
  }
  return dimension;
}

float Detector::calculateModuleSize(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft) {
  // Take the average
  return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;
}

float Detector::calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPoint> otherPattern) {
  float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(),
                         (int)otherPattern->getX(), (int)otherPattern->getY());
  float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(),
                         (int)pattern->getX(), (int)pattern->getY());
  if (isnan(moduleSizeEst1)) {
    return moduleSizeEst2;
  }
  if (isnan(moduleSizeEst2)) {
    return moduleSizeEst1;
  }
  // Average them, and divide by 7 since we've counted the width of 3 black modules,
  // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
  return (moduleSizeEst1 + moduleSizeEst2) / 14.0f;
}

float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) {

   float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);

   // Now count other way -- don't run off image though of course
   float scale = 1.0f;
   int otherToX = fromX - (toX - fromX);
   if (otherToX < 0) {
     scale = (float) fromX / (float) (fromX - otherToX);
     otherToX = 0;
   } else if (otherToX > (int)image_->getWidth()) {
     scale = (float) (image_->getWidth() - fromX) / (float) (otherToX - fromX);
     otherToX = image_->getWidth();
   }
   int otherToY = (int) (fromY - (toY - fromY) * scale);

   scale = 1.0f;
   if (otherToY < 0) {
     scale = (float) fromY / (float) (fromY - otherToY);
     otherToY = 0;
   } else if (otherToY > (int)image_->getHeight()) {
     scale = (float) (image_->getHeight() - fromY) / (float) (otherToY - fromY);
     otherToY = image_->getHeight();
   }
   otherToX = (int) (fromX + (otherToX - fromX) * scale);

   result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
   return result;
}

float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) {
  // Mild variant of Bresenham's algorithm;
  // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
  bool steep = abs(toY - fromY) > abs(toX - fromX);
  if (steep) {
    int temp = fromX;
    fromX = fromY;
    fromY = temp;
    temp = toX;
    toX = toY;
    toY = temp;
  }

  int dx = abs(toX - fromX);
  int dy = abs(toY - fromY);
  int error = -dx >> 1;
  int ystep = fromY < toY ? 1 : -1;
  int xstep = fromX < toX ? 1 : -1;
  int state = 0; // In black pixels, looking for white, first or second time
  for (int x = fromX, y = fromY; x != toX; x += xstep) {

    int realX = steep ? y : x;
    int realY = steep ? x : y;
    if (state == 1) { // In white pixels, looking for black
      if (image_->get(realX, realY)) {
        state++;
      }
    } else {
      if (!image_->get(realX, realY)) {
        state++;
      }
    }

    if (state == 3) { // Found black, white, black, and stumbled back onto white; done
      int diffX = x - fromX;
      int diffY = y - fromY;
      if (xstep < 0) {
          diffX++;
      }
      return (float)sqrt((double)(diffX * diffX + diffY * diffY));
    }
    error += dy;
    if (error > 0) {
      y += ystep;
      error -= dx;
    }
  }
  int diffX = toX - fromX;
  int diffY = toY - fromY;
  return (float)sqrt((double)(diffX * diffX + diffY * diffY));
}

Ref<AlignmentPattern> Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,
    float allowanceFactor) {
  // Look for an alignment pattern (3 modules in size) around where it
  // should be
  int allowance = (int)(allowanceFactor * overallEstModuleSize);
  int alignmentAreaLeftX = max(0, estAlignmentX - allowance);
  int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance);
  if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
      throw zxing::ReaderException("region too small to hold alignment pattern");
  }
  int alignmentAreaTopY = max(0, estAlignmentY - allowance);
  int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);
  if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) {
      throw zxing::ReaderException("region too small to hold alignment pattern");
  }

  AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX
                                         - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_);
  return alignmentFinder.find();
}

}
}
<commit_msg>Port Java qr detector changes<commit_after>/*
 *  Detector.cpp
 *  zxing
 *
 *  Created by Christian Brunschen on 14/05/2008.
 *  Copyright 2008 ZXing authors All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/qrcode/detector/Detector.h>
#include <zxing/qrcode/detector/FinderPatternFinder.h>
#include <zxing/qrcode/detector/FinderPattern.h>
#include <zxing/qrcode/detector/AlignmentPattern.h>
#include <zxing/qrcode/detector/AlignmentPatternFinder.h>
#include <zxing/qrcode/Version.h>
#include <zxing/common/GridSampler.h>
#include <zxing/DecodeHints.h>
#include <cmath>
#include <sstream>
#include <cstdlib>

namespace zxing {
namespace qrcode {

using namespace std;

Detector::Detector(Ref<BitMatrix> image) :
    image_(image) {
}

Ref<BitMatrix> Detector::getImage() {
   return image_;
}

Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
  callback_ = hints.getResultPointCallback();
  FinderPatternFinder finder(image_, hints.getResultPointCallback());
  Ref<FinderPatternInfo> info(finder.find(hints));

  Ref<FinderPattern> topLeft(info->getTopLeft());
  Ref<FinderPattern> topRight(info->getTopRight());
  Ref<FinderPattern> bottomLeft(info->getBottomLeft());

  float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);
  if (moduleSize < 1.0f) {
    throw zxing::ReaderException("bad module size");
  }
  int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
  Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension);
  int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7;

  Ref<AlignmentPattern> alignmentPattern;
  // Anything above version 1 has an alignment pattern
  if (provisionalVersion->getAlignmentPatternCenters().size() > 0) {

    // Guess where a "bottom right" finder pattern would have been
    float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX();
    float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY();

    // Estimate that alignment pattern is closer by 3 modules
    // from "bottom right" to known top left location
    float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters;
    int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX()));
    int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY()));

    // Kind of arbitrary -- expand search radius before giving up
    for (int i = 4; i <= 16; i <<= 1) {
      try {
        alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i);
        break;
      } catch (zxing::ReaderException re) {
        // try next round
      }
    }
    if (alignmentPattern == 0) {
      // Try anyway
    }

  }

  Ref<PerspectiveTransform> transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
  Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
  std::vector<Ref<ResultPoint> > points(alignmentPattern == 0 ? 3 : 4);
  points[0].reset(bottomLeft);
  points[1].reset(topLeft);
  points[2].reset(topRight);
  if (alignmentPattern != 0) {
    points[3].reset(alignmentPattern);
  }

  Ref<DetectorResult> result(new DetectorResult(bits, points, transform));
  return result;
}

Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
    ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {

  float dimMinusThree = (float)dimension - 3.5f;
  float bottomRightX;
  float bottomRightY;
  float sourceBottomRightX;
  float sourceBottomRightY;
  if (alignmentPattern != 0) {
    bottomRightX = alignmentPattern->getX();
    bottomRightY = alignmentPattern->getY();
    sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
  } else {
    // Don't have an alignment pattern, just make up the bottom-right point
    bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX();
    bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY();
    sourceBottomRightX = sourceBottomRightY = dimMinusThree;
  }

  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX,
                                      sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(),
                                      topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY()));

  return transform;
}

Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {
  GridSampler &sampler = GridSampler::getInstance();
  return sampler.sampleGrid(image, dimension, transform);
}

int Detector::computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,
                               float moduleSize) {
  int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f);
  int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f);
  int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
  switch (dimension & 0x03) { // mod 4
  case 0:
    dimension++;
    break;
    // 1? do nothing
  case 2:
    dimension--;
    break;
  case 3:
    ostringstream s;
    s << "Bad dimension: " << dimension;
    throw zxing::ReaderException(s.str().c_str());
  }
  return dimension;
}

float Detector::calculateModuleSize(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft) {
  // Take the average
  return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;
}

float Detector::calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPoint> otherPattern) {
  float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(),
                         (int)otherPattern->getX(), (int)otherPattern->getY());
  float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(),
                         (int)pattern->getX(), (int)pattern->getY());
  if (isnan(moduleSizeEst1)) {
    return moduleSizeEst2;
  }
  if (isnan(moduleSizeEst2)) {
    return moduleSizeEst1;
  }
  // Average them, and divide by 7 since we've counted the width of 3 black modules,
  // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
  return (moduleSizeEst1 + moduleSizeEst2) / 14.0f;
}

float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) {

    float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);

    // Now count other way -- don't run off image though of course
    float scale = 1.0f;
    int otherToX = fromX - (toX - fromX);
    if (otherToX < 0) {
      scale = (float) fromX / (float) (fromX - otherToX);
      otherToX = 0;
    } else if (otherToX >= (int)image_->getWidth()) {
      scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX);
      otherToX = image_->getWidth() - 1;
    }
    int otherToY = (int) (fromY - (toY - fromY) * scale);

    scale = 1.0f;
    if (otherToY < 0) {
      scale = (float) fromY / (float) (fromY - otherToY);
      otherToY = 0;
    } else if (otherToY >= (int)image_->getHeight()) {
      scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY);
      otherToY = image_->getHeight() - 1;
    }
    otherToX = (int) (fromX + (otherToX - fromX) * scale);

    result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);

    // Middle pixel is double-counted this way; subtract 1
    return result - 1.0f;
}

float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) {
    // Mild variant of Bresenham's algorithm;
    // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
    bool steep = abs(toY - fromY) > abs(toX - fromX);
    if (steep) {
      int temp = fromX;
      fromX = fromY;
      fromY = temp;
      temp = toX;
      toX = toY;
      toY = temp;
    }

    int dx = abs(toX - fromX);
    int dy = abs(toY - fromY);
    int error = -dx >> 1;
    int xstep = fromX < toX ? 1 : -1;
    int ystep = fromY < toY ? 1 : -1;

    // In black pixels, looking for white, first or second time.
    int state = 0;
    // Loop up until x == toX, but not beyond
    int xLimit = toX + xstep;
    for (int x = fromX, y = fromY; x != xLimit; x += xstep) {
      int realX = steep ? y : x;
      int realY = steep ? x : y;

      // Does current pixel mean we have moved white to black or vice versa?
      if (!(state == 1 ^ image_->get(realX, realY))) {
        if (state == 2) {
          int diffX = x - fromX;
          int diffY = y - fromY;
          return (float) sqrt((double) (diffX * diffX + diffY * diffY));
        }
        state++;
      }

      error += dy;
      if (error > 0) {
        if (y == toY) {
          break;
        }
        y += ystep;
        error -= dx;
      }
    }
    // Found black-white-black; give the benefit of the doubt that the next pixel outside the image
    // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
    // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
    if (state == 2) {
      int diffX = toX + xstep - fromX;
      int diffY = toY - fromY;
      return (float) sqrt((double) (diffX * diffX + diffY * diffY));
    }
    // else we didn't find even black-white-black; no estimate is really possible
    return NAN;
}

Ref<AlignmentPattern> Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,
    float allowanceFactor) {
  // Look for an alignment pattern (3 modules in size) around where it
  // should be
  int allowance = (int)(allowanceFactor * overallEstModuleSize);
  int alignmentAreaLeftX = max(0, estAlignmentX - allowance);
  int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance);
  if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
      throw zxing::ReaderException("region too small to hold alignment pattern");
  }
  int alignmentAreaTopY = max(0, estAlignmentY - allowance);
  int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);
  if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) {
      throw zxing::ReaderException("region too small to hold alignment pattern");
  }

  AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX
                                         - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_);
  return alignmentFinder.find();
}

}
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "IncrementalParser.h"
#include "ASTDumper.h"
#include "ASTNodeEraser.h"
#include "DeclCollector.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "ReturnSynthesizer.h"
#include "ValuePrinterSynthesizer.h"
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Parse/Parser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Serialization/ASTWriter.h"

#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"

#include <ctime>
#include <iostream>
#include <stdio.h>
#include <sstream>

using namespace clang;

namespace cling {
  IncrementalParser::IncrementalParser(Interpreter* interp,
                                       int argc, const char* const *argv,
                                       const char* llvmdir):
    m_Interpreter(interp), m_Consumer(0), m_FirstTransaction(0),
    m_LastTransaction(0) {

    CompilerInstance* CI
      = CIFactory::createCI(llvm::MemoryBuffer::getMemBuffer("", "CLING"),
                            argc, argv, llvmdir);
    assert(CI && "CompilerInstance is (null)!");

    m_Consumer = dyn_cast<DeclCollector>(&CI->getASTConsumer());
    assert(m_Consumer && "Expected ChainedConsumer!");

    m_CI.reset(CI);

    if (CI->getFrontendOpts().ProgramAction != clang::frontend::ParseSyntaxOnly){
      m_CodeGen.reset(CreateLLVMCodeGen(CI->getDiagnostics(), "cling input",
                                        CI->getCodeGenOpts(),
                                        *m_Interpreter->getLLVMContext()
                                        ));
    }

    CreateSLocOffsetGenerator();

    // Add transformers to the IncrementalParser, which owns them
    m_TTransformers.push_back(new EvaluateTSynthesizer(&CI->getSema()));

    m_TTransformers.push_back(new ValuePrinterSynthesizer(&CI->getSema(), 0));
    m_TTransformers.push_back(new ReturnSynthesizer(&CI->getSema()));
    m_TTransformers.push_back(new ASTDumper());
    m_TTransformers.push_back(new DeclExtractor(&getCI()->getSema()));

    m_Parser.reset(new Parser(CI->getPreprocessor(), CI->getSema(),
                              false /*skipFuncBodies*/));
    CI->getPreprocessor().EnterMainSourceFile();
    // Initialize the parser after we have entered the main source file.
    m_Parser->Initialize();
    // Perform initialization that occurs after the parser has been initialized
    // but before it parses anything. Initializes the consumers too.
    CI->getSema().Initialize();
  }

  IncrementalParser::~IncrementalParser() {
     if (hasCodeGenerator()) {
       getCodeGenerator()->ReleaseModule();
     }
     const Transaction* T = getFirstTransaction();
     const Transaction* nextT = 0;
     while (T) {
       nextT = T->getNext();
       delete T;
       T = nextT;
     }

     for (size_t i = 0; i < m_TTransformers.size(); ++i)
       delete m_TTransformers[i];
  }

  void IncrementalParser::beginTransaction(const CompilationOptions& Opts) {
    llvm::Module* M = 0;
    if (hasCodeGenerator())
      M = getCodeGenerator()->GetModule();

    Transaction* NewCurT = new Transaction(Opts, M);
    Transaction* OldCurT = m_Consumer->getTransaction();
    m_Consumer->setTransaction(NewCurT);
    // If we are in the middle of transaction and we see another begin
    // transaction - it must be nested transaction.
    if (OldCurT && !OldCurT->isCompleted()) {
      OldCurT->addNestedTransaction(NewCurT); // takes the ownership
      return;
    }

    if (!m_FirstTransaction) {
      m_FirstTransaction = NewCurT;
      m_LastTransaction = NewCurT;
    }
    else {
      m_LastTransaction->setNext(NewCurT);
      m_LastTransaction = NewCurT;
    }
  }

  void IncrementalParser::endTransaction() const {
    Transaction* CurT = m_Consumer->getTransaction();
    CurT->setCompleted();
    const DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics();

    //TODO: Make the enum orable.
    if (Diags.getNumWarnings() > 0)
      CurT->setIssuedDiags(Transaction::kWarnings);

    if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
      CurT->setIssuedDiags(Transaction::kErrors);

    if (CurT->isNestedTransaction()) {
      assert(!CurT->getParent()->isCompleted()
             && "Parent transaction completed!?");
      // FIXME: Not sure what I meant :) REVISIT
      //CurT = m_Consumer->getTransaction()->getParent();
    }
  }

  void IncrementalParser::commitCurrentTransaction() {
    Transaction* CurT = m_Consumer->getTransaction();
    assert(CurT->isCompleted() && "Transaction not ended!?");

    // Check for errors...
    if (CurT->getIssuedDiags() == Transaction::kErrors) {
      rollbackTransaction(CurT);
      return;
    }

    // Check for errors coming from our custom consumers.
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();
    DClient.BeginSourceFile(getCI()->getLangOpts(),
                            &getCI()->getPreprocessor());

    // We are sure it's safe to pipe it through the transformers
    bool success = true;
    for (size_t i = 0; i < m_TTransformers.size(); ++i)
      if (!m_TTransformers[i]->TransformTransaction(*CurT)) {
        success = false;
        break;
      }

    DClient.EndSourceFile();
    m_CI->getDiagnostics().Reset(); // FIXME: Should be in rollback transaction.

    if (!success) {
      // Roll back on error in a transformer
      rollbackTransaction(CurT);
      return;
    }

    // Pull all template instantiations in that came from the consumers.
    getCI()->getSema().PerformPendingInstantiations();

    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    if (CurT->getCompilationOpts().CodeGeneration && hasCodeGenerator()) {
      // Reset the module builder to clean up global initializers, c'tors, d'tors
      getCodeGenerator()->Initialize(getCI()->getASTContext());

      // codegen the transaction
      for (Transaction::const_iterator I = CurT->decls_begin(),
             E = CurT->decls_end(); I != E; ++I) {
        getCodeGenerator()->HandleTopLevelDecl(*I);
      }
      getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext());
      // run the static initializers that came from codegenning
      m_Interpreter->runStaticInitializersOnce();
    }

    CurT->setState(Transaction::kCommitted);
    InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks();
    if (callbacks)
      callbacks->TransactionCommitted(*CurT);
  }

  void IncrementalParser::rollbackTransaction(Transaction* T) const {
    ASTNodeEraser NodeEraser(&getCI()->getSema());

    if (NodeEraser.RevertTransaction(T))
      T->setState(Transaction::kRolledBack);
    else
      T->setState(Transaction::kRolledBackWithErrors);
  }

  // Each input line is contained in separate memory buffer. The SourceManager
  // assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry
  // for the MemoryBuffer's FileID. That in turn is problem because invalid
  // SourceLocations are given to the diagnostics. Thus the diagnostics cannot
  // order the overloads, for example
  //
  // Our work-around is creating a virtual file, which doesn't exist on the disk
  // with enormous size (no allocation is done). That file has valid FileEntry
  // and so on... We use it for generating valid SourceLocations with valid
  // offsets so that it doesn't cause any troubles to the diagnostics.
  //
  // +---------------------+
  // | Main memory buffer  |
  // +---------------------+
  // |  Virtual file SLoc  |
  // |    address space    |<-----------------+
  // |         ...         |<------------+    |
  // |         ...         |             |    |
  // |         ...         |<----+       |    |
  // |         ...         |     |       |    |
  // +~~~~~~~~~~~~~~~~~~~~~+     |       |    |
  // |     input_line_1    | ....+.......+..--+
  // +---------------------+     |       |
  // |     input_line_2    | ....+.....--+
  // +---------------------+     |
  // |          ...        |     |
  // +---------------------+     |
  // |     input_line_N    | ..--+
  // +---------------------+
  //
  void IncrementalParser::CreateSLocOffsetGenerator() {
    SourceManager& SM = getCI()->getSourceManager();
    FileManager& FM = SM.getFileManager();
    const FileEntry* FE
      = FM.getVirtualFile("InteractiveInputLineIncluder.h", 1U << 15U, time(0));
    m_VirtualFileID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);

    assert(!m_VirtualFileID.isInvalid() && "No VirtualFileID created?");
  }

  IncrementalParser::EParseResult
  IncrementalParser::Compile(llvm::StringRef input,
                             const CompilationOptions& Opts) {

    beginTransaction(Opts);
    EParseResult Result = ParseInternal(input);
    endTransaction();

    commitCurrentTransaction();

    return Result;
  }

  Transaction* IncrementalParser::Parse(llvm::StringRef input,
                                        const CompilationOptions& Opts) {
    beginTransaction(Opts);
    ParseInternal(input);
    endTransaction();

    return getLastTransaction();
  }

  // Add the input to the memory buffer, parse it, and add it to the AST.
  IncrementalParser::EParseResult
  IncrementalParser::ParseInternal(llvm::StringRef input) {
    if (input.empty()) return IncrementalParser::kSuccess;

    PrettyStackTraceParserEntry CrashInfo(*m_Parser.get());

    // Recover resources if we crash before exiting this method.
    llvm::CrashRecoveryContextCleanupRegistrar<Parser>
      CleanupParser(m_Parser.get());

    Sema& S = getCI()->getSema();
    // Recover resources if we crash before exiting this method.
    llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);

    Preprocessor& PP = m_CI->getPreprocessor();
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    if (!PP.getCurrentLexer()) {
       PP.EnterSourceFile(m_CI->getSourceManager().getMainFileID(),
                          0, SourceLocation());
    }
    assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
    PP.enableIncrementalProcessing();

    DClient.BeginSourceFile(m_CI->getLangOpts(), &PP);

    std::ostringstream source_name;
    source_name << "input_line_" << (m_MemoryBuffers.size() + 1);

    // Create an uninitialized memory buffer, copy code in and append "\n"
    size_t InputSize = input.size(); // don't include trailing 0
    // MemBuffer size should *not* include terminating zero
    llvm::MemoryBuffer* MB
      = llvm::MemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
                                                  source_name.str());
    char* MBStart = const_cast<char*>(MB->getBufferStart());
    memcpy(MBStart, input.data(), InputSize);
    memcpy(MBStart + InputSize, "\n", 2);

    m_MemoryBuffers.push_back(MB);
    SourceManager& SM = getCI()->getSourceManager();

    // Create SourceLocation, which will allow clang to order the overload
    // candidates for example
    SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
    NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffers.size() + 1);

    // Create FileID for the current buffer
    FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffers.back(),
                                             /*LoadedID*/0,
                                             /*LoadedOffset*/0, NewLoc);

    PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl)
        m_Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
    };

    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(),
           E = S.WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    S.PerformPendingInstantiations();

    DClient.EndSourceFile();

    DiagnosticsEngine& Diag = S.getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }

  void IncrementalParser::unloadTransaction(Transaction* T) {
    if (!T)
      T = getLastTransaction();

    assert(T->getState() == Transaction::kCommitted &&
           "Unloading not commited transaction?");
    assert(T->getModule() &&
           "Trying to uncodegen transaction taken in syntax only mode. ");

    ASTNodeEraser NodeEraser(&getCI()->getSema());
    NodeEraser.RevertTransaction(T);

    InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks();
    if (callbacks)
      callbacks->TransactionUnloaded(*T);
  }

} // namespace cling
<commit_msg>End close the file for diagnostics at proper time.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "IncrementalParser.h"
#include "ASTDumper.h"
#include "ASTNodeEraser.h"
#include "DeclCollector.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "ReturnSynthesizer.h"
#include "ValuePrinterSynthesizer.h"
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Parse/Parser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Serialization/ASTWriter.h"

#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"

#include <ctime>
#include <iostream>
#include <stdio.h>
#include <sstream>

using namespace clang;

namespace cling {
  IncrementalParser::IncrementalParser(Interpreter* interp,
                                       int argc, const char* const *argv,
                                       const char* llvmdir):
    m_Interpreter(interp), m_Consumer(0), m_FirstTransaction(0),
    m_LastTransaction(0) {

    CompilerInstance* CI
      = CIFactory::createCI(llvm::MemoryBuffer::getMemBuffer("", "CLING"),
                            argc, argv, llvmdir);
    assert(CI && "CompilerInstance is (null)!");

    m_Consumer = dyn_cast<DeclCollector>(&CI->getASTConsumer());
    assert(m_Consumer && "Expected ChainedConsumer!");

    m_CI.reset(CI);

    if (CI->getFrontendOpts().ProgramAction != clang::frontend::ParseSyntaxOnly){
      m_CodeGen.reset(CreateLLVMCodeGen(CI->getDiagnostics(), "cling input",
                                        CI->getCodeGenOpts(),
                                        *m_Interpreter->getLLVMContext()
                                        ));
    }

    CreateSLocOffsetGenerator();

    // Add transformers to the IncrementalParser, which owns them
    m_TTransformers.push_back(new EvaluateTSynthesizer(&CI->getSema()));

    m_TTransformers.push_back(new ValuePrinterSynthesizer(&CI->getSema(), 0));
    m_TTransformers.push_back(new ReturnSynthesizer(&CI->getSema()));
    m_TTransformers.push_back(new ASTDumper());
    m_TTransformers.push_back(new DeclExtractor(&getCI()->getSema()));

    m_Parser.reset(new Parser(CI->getPreprocessor(), CI->getSema(),
                              false /*skipFuncBodies*/));
    CI->getPreprocessor().EnterMainSourceFile();
    // Initialize the parser after we have entered the main source file.
    m_Parser->Initialize();
    // Perform initialization that occurs after the parser has been initialized
    // but before it parses anything. Initializes the consumers too.
    CI->getSema().Initialize();
  }

  IncrementalParser::~IncrementalParser() {
     if (hasCodeGenerator()) {
       getCodeGenerator()->ReleaseModule();
     }
     const Transaction* T = getFirstTransaction();
     const Transaction* nextT = 0;
     while (T) {
       nextT = T->getNext();
       delete T;
       T = nextT;
     }

     for (size_t i = 0; i < m_TTransformers.size(); ++i)
       delete m_TTransformers[i];
  }

  void IncrementalParser::beginTransaction(const CompilationOptions& Opts) {
    llvm::Module* M = 0;
    if (hasCodeGenerator())
      M = getCodeGenerator()->GetModule();

    Transaction* NewCurT = new Transaction(Opts, M);
    Transaction* OldCurT = m_Consumer->getTransaction();
    m_Consumer->setTransaction(NewCurT);
    // If we are in the middle of transaction and we see another begin
    // transaction - it must be nested transaction.
    if (OldCurT && !OldCurT->isCompleted()) {
      OldCurT->addNestedTransaction(NewCurT); // takes the ownership
      return;
    }

    if (!m_FirstTransaction) {
      m_FirstTransaction = NewCurT;
      m_LastTransaction = NewCurT;
    }
    else {
      m_LastTransaction->setNext(NewCurT);
      m_LastTransaction = NewCurT;
    }
  }

  void IncrementalParser::endTransaction() const {
    Transaction* CurT = m_Consumer->getTransaction();
    CurT->setCompleted();
    const DiagnosticsEngine& Diags = getCI()->getSema().getDiagnostics();

    //TODO: Make the enum orable.
    if (Diags.getNumWarnings() > 0)
      CurT->setIssuedDiags(Transaction::kWarnings);

    if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
      CurT->setIssuedDiags(Transaction::kErrors);

    if (CurT->isNestedTransaction()) {
      assert(!CurT->getParent()->isCompleted()
             && "Parent transaction completed!?");
      // FIXME: Not sure what I meant :) REVISIT
      //CurT = m_Consumer->getTransaction()->getParent();
    }
  }

  void IncrementalParser::commitCurrentTransaction() {
    Transaction* CurT = m_Consumer->getTransaction();
    assert(CurT->isCompleted() && "Transaction not ended!?");

    // Check for errors coming from our custom consumers.
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    // Check for errors...
    if (CurT->getIssuedDiags() == Transaction::kErrors) {
      rollbackTransaction(CurT);
      DClient.EndSourceFile();
      return;
    }

    // We are sure it's safe to pipe it through the transformers
    bool success = true;
    for (size_t i = 0; i < m_TTransformers.size(); ++i) {
      DClient.BeginSourceFile(getCI()->getLangOpts(),
                              &getCI()->getPreprocessor());
      success = m_TTransformers[i]->TransformTransaction(*CurT);
      DClient.EndSourceFile();
      if (!success) {
        break;
      }
    }

    m_CI->getDiagnostics().Reset(); // FIXME: Should be in rollback transaction.

    if (!success) {
      // Roll back on error in a transformer
      rollbackTransaction(CurT);
      DClient.EndSourceFile();
      return;
    }

    // Pull all template instantiations in that came from the consumers.
    getCI()->getSema().PerformPendingInstantiations();
    DClient.EndSourceFile();

    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    if (CurT->getCompilationOpts().CodeGeneration && hasCodeGenerator()) {
      // Reset the module builder to clean up global initializers, c'tors, d'tors
      getCodeGenerator()->Initialize(getCI()->getASTContext());

      // codegen the transaction
      for (Transaction::const_iterator I = CurT->decls_begin(),
             E = CurT->decls_end(); I != E; ++I) {
        getCodeGenerator()->HandleTopLevelDecl(*I);
      }
      getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext());
      // run the static initializers that came from codegenning
      m_Interpreter->runStaticInitializersOnce();
    }

    CurT->setState(Transaction::kCommitted);
    InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks();

    if (callbacks)
      callbacks->TransactionCommitted(*CurT);
  }

  void IncrementalParser::rollbackTransaction(Transaction* T) const {
    ASTNodeEraser NodeEraser(&getCI()->getSema());

    if (NodeEraser.RevertTransaction(T))
      T->setState(Transaction::kRolledBack);
    else
      T->setState(Transaction::kRolledBackWithErrors);
  }

  // Each input line is contained in separate memory buffer. The SourceManager
  // assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry
  // for the MemoryBuffer's FileID. That in turn is problem because invalid
  // SourceLocations are given to the diagnostics. Thus the diagnostics cannot
  // order the overloads, for example
  //
  // Our work-around is creating a virtual file, which doesn't exist on the disk
  // with enormous size (no allocation is done). That file has valid FileEntry
  // and so on... We use it for generating valid SourceLocations with valid
  // offsets so that it doesn't cause any troubles to the diagnostics.
  //
  // +---------------------+
  // | Main memory buffer  |
  // +---------------------+
  // |  Virtual file SLoc  |
  // |    address space    |<-----------------+
  // |         ...         |<------------+    |
  // |         ...         |             |    |
  // |         ...         |<----+       |    |
  // |         ...         |     |       |    |
  // +~~~~~~~~~~~~~~~~~~~~~+     |       |    |
  // |     input_line_1    | ....+.......+..--+
  // +---------------------+     |       |
  // |     input_line_2    | ....+.....--+
  // +---------------------+     |
  // |          ...        |     |
  // +---------------------+     |
  // |     input_line_N    | ..--+
  // +---------------------+
  //
  void IncrementalParser::CreateSLocOffsetGenerator() {
    SourceManager& SM = getCI()->getSourceManager();
    FileManager& FM = SM.getFileManager();
    const FileEntry* FE
      = FM.getVirtualFile("InteractiveInputLineIncluder.h", 1U << 15U, time(0));
    m_VirtualFileID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);

    assert(!m_VirtualFileID.isInvalid() && "No VirtualFileID created?");
  }

  IncrementalParser::EParseResult
  IncrementalParser::Compile(llvm::StringRef input,
                             const CompilationOptions& Opts) {

    beginTransaction(Opts);
    EParseResult Result = ParseInternal(input);
    endTransaction();

    commitCurrentTransaction();

    return Result;
  }

  Transaction* IncrementalParser::Parse(llvm::StringRef input,
                                        const CompilationOptions& Opts) {
    beginTransaction(Opts);
    ParseInternal(input);
    endTransaction();

    return getLastTransaction();
  }

  // Add the input to the memory buffer, parse it, and add it to the AST.
  IncrementalParser::EParseResult
  IncrementalParser::ParseInternal(llvm::StringRef input) {
    if (input.empty()) return IncrementalParser::kSuccess;

    PrettyStackTraceParserEntry CrashInfo(*m_Parser.get());

    // Recover resources if we crash before exiting this method.
    llvm::CrashRecoveryContextCleanupRegistrar<Parser>
      CleanupParser(m_Parser.get());

    Sema& S = getCI()->getSema();
    // Recover resources if we crash before exiting this method.
    llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);

    Preprocessor& PP = m_CI->getPreprocessor();
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    if (!PP.getCurrentLexer()) {
       PP.EnterSourceFile(m_CI->getSourceManager().getMainFileID(),
                          0, SourceLocation());
    }
    assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
    PP.enableIncrementalProcessing();

    DClient.BeginSourceFile(m_CI->getLangOpts(), &PP);

    std::ostringstream source_name;
    source_name << "input_line_" << (m_MemoryBuffers.size() + 1);

    // Create an uninitialized memory buffer, copy code in and append "\n"
    size_t InputSize = input.size(); // don't include trailing 0
    // MemBuffer size should *not* include terminating zero
    llvm::MemoryBuffer* MB
      = llvm::MemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
                                                  source_name.str());
    char* MBStart = const_cast<char*>(MB->getBufferStart());
    memcpy(MBStart, input.data(), InputSize);
    memcpy(MBStart + InputSize, "\n", 2);

    m_MemoryBuffers.push_back(MB);
    SourceManager& SM = getCI()->getSourceManager();

    // Create SourceLocation, which will allow clang to order the overload
    // candidates for example
    SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
    NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffers.size() + 1);

    // Create FileID for the current buffer
    FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffers.back(),
                                             /*LoadedID*/0,
                                             /*LoadedOffset*/0, NewLoc);

    PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl)
        m_Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
    };

    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(),
           E = S.WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    S.PerformPendingInstantiations();

    DiagnosticsEngine& Diag = S.getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }

  void IncrementalParser::unloadTransaction(Transaction* T) {
    if (!T)
      T = getLastTransaction();

    assert(T->getState() == Transaction::kCommitted &&
           "Unloading not commited transaction?");
    assert(T->getModule() &&
           "Trying to uncodegen transaction taken in syntax only mode. ");

    ASTNodeEraser NodeEraser(&getCI()->getSema());
    NodeEraser.RevertTransaction(T);

    InterpreterCallbacks* callbacks = m_Interpreter->getCallbacks();
    if (callbacks)
      callbacks->TransactionUnloaded(*T);
  }

} // namespace cling
<|endoftext|>