<commit_before>#include "../res-files/std_lib_facilities.h"

/*
	Write a program that takes an operation followed by two operands and outputs the result. For example:
		+ 100 3.14
		* 4 5

	Read the operation into a string called operation and use an if-statement to figure out which operation the user wants, for example, if (operation=="+"). Read the operands
	into variables of type double. Implement this for operations called +, –, *, /, plus, minus, mul, and div with their obvious meanings.
*/

int main() {
	// tell the user wtf to input now
	cout << "Smooth operator, baby! Give me an operation, followed by two operands."
		<< "\nOperators should be +, -, *, /, plus, minus, mul, or div. Operands should be reg'la' floating point numbers.\n\n";
	// variables to hold our operator and operands
	string strGivenSymbol;
	double dblNumberOne;
	double dblNumberTwo;
	// receive the things, and write them into the variables
	cin >> strGivenSymbol >> dblNumberOne >> dblNumberTwo;
	// determine what to do, based on the operator supplied, and store that in another variable
	// this would be much neater if I could use OR's
	string charActualSymbol;
	// determine addition
	if (strGivenSymbol == "+") {
		charActualSymbol = '+';
	}
	if (strGivenSymbol == "plus") {
		charActualSymbol = '+';
	}
	// determine subtraction
	if (strGivenSymbol == "-") {
		charActualSymbol = '-';
	}
	if (strGivenSymbol == "minus") {
		charActualSymbol = '-';
	}
	// determine multiplication
	if (strGivenSymbol == "*") {
		charActualSymbol = '*';
	}
	if (strGivenSymbol == "mul") {
		charActualSymbol = '*';
	}
	// determine division
	if (strGivenSymbol == "/") {
		charActualSymbol = '/';
	}
	if (strGivenSymbol == "div") {
		charActualSymbol = '/';
	}

	// finally, perform the calculation and store the answer
	double dblAnswer = (dblNumberOne charActualSymbol dblNumberTwo);

	// display the calculation and answer
	cout << "Calculating: " << dblNumberOne << " " << strGivenSymbol << " " << dblNumberTwo << " = " << dblAnswer << '\n';
}

/*
	strange thing: I originally used single-quotes/apostrophes to enclose the operand characters, eg. '*' rather than "*". This seems to have been a problem, with the compiler
	throwing tons of errors. Perhaps that kind of quote must be used with chars and not strings...
*/<commit_msg>some edits to c03 q10<commit_after>#include "../res-files/std_lib_facilities.h"

/*
	Write a program that takes an operation followed by two operands and outputs the result. For example:
		+ 100 3.14
		* 4 5

	Read the operation into a string called operation and use an if-statement to figure out which operation the user wants, for example, if (operation=="+"). Read the operands
	into variables of type double. Implement this for operations called +, –, *, /, plus, minus, mul, and div with their obvious meanings.
*/

int main() {
	// tell the user wtf to input now
	cout << "Smooth operator, baby! Give me an operation, followed by two operands."
		<< "\nOperators should be +, -, *, /, plus, minus, mul, or div. Operands should be reg'la' floating point numbers.\n\n";
	// variables to hold our operator and operands
	string strGivenSymbol;
	double dblNumberOne;
	double dblNumberTwo;
	// receive the things, and write them into the variables
	cin >> strGivenSymbol >> dblNumberOne >> dblNumberTwo;
	// determine what to do, based on the operator supplied, and store that in another variable
	// this would be much neater if I could use OR's
	string charActualSymbol;
	// determine addition
	if (strGivenSymbol == "+") {
		charActualSymbol = '+';
	}
	if (strGivenSymbol == "plus") {
		charActualSymbol = '+';
	}
	// determine subtraction
	if (strGivenSymbol == "-") {
		charActualSymbol = '-';
	}
	if (strGivenSymbol == "minus") {
		charActualSymbol = '-';
	}
	// determine multiplication
	if (strGivenSymbol == "*") {
		charActualSymbol = '*';
	}
	if (strGivenSymbol == "mul") {
		charActualSymbol = '*';
	}
	// determine division
	if (strGivenSymbol == "/") {
		charActualSymbol = '/';
	}
	if (strGivenSymbol == "div") {
		charActualSymbol = '/';
	}

	// finally, perform the calculation and store the answer
	double dblAnswer;
	dblAnswer = dblNumberOne charActualSymbol dblNumberTwo;

	// display the calculation and answer
	cout << "Calculating: " << dblNumberOne << " " << strGivenSymbol << " " << dblNumberTwo << " = " << dblAnswer << '\n';
}

/*
	strange thing: I originally used single-quotes/apostrophes to enclose the operand characters, eg. '*' rather than "*". This seems to have been a problem, with the compiler
	throwing tons of errors. Perhaps that kind of quote must be used with chars and not strings...
*/
<|endoftext|>


<commit_before>/*!
  \copyright (c) RDO-Team, 2011
  \file      rdofile.inl
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (lord.tiran@gmail.com)
  \date      10.05.2009
  \brief
  \indent    4T
*/

// ----------------------------------------------------------------------- PLATFORM
#include "utils/platform.h"
// ----------------------------------------------------------------------- INCLUDES
#ifdef OST_WINDOWS
        #include <io.h>
#else
        #include <unistd.h>
#endif

#include <fstream>
#include <boost/filesystem.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "utils/namespace.h"
#include "utils/rdotypes.h"
#include "utils/rdomacros.h"
// --------------------------------------------------------------------------------

OPEN_RDO_NAMESPACE

inline rbool File::create(CREF(tstring) name)
{
	return create(name, _T(""));
}

inline rbool File::create(CREF(tstring) name, CREF(tstring) content)
{
	std::ofstream file(name.c_str(), std::ios::out | std::ios::binary);
	file << content.c_str() << std::endl;
	file.close();
	return true;
}

inline rbool File::exist(CREF(tstring) name)
{
	return  boost::filesystem::exists(name.c_str());
}

inline rbool File::read_only(CREF(tstring) name)
{
#ifdef OST_WINDOWS
	return _access(name.c_str(), 04) == 0 && _access(name.c_str(), 06) == -1;
#else  // not OST_WINDOWS
	return access(name.c_str(), R_OK) == 0 && access(name.c_str(), W_OK) == -1;
#endif // OST_WINDOWS
}

inline rbool File::unlink(CREF(tstring) name)
{
	return boost::filesystem::remove(name.c_str());
}

CLOSE_RDO_NAMESPACE
<commit_msg> - форматирование<commit_after>/*!
  \copyright (c) RDO-Team, 2011
  \file      rdofile.inl
  \authors     (rdo@rk9.bmstu.ru)
  \authors     (lord.tiran@gmail.com)
  \date      10.05.2009
  \brief
  \indent    4T
*/

// ----------------------------------------------------------------------- PLATFORM
#include "utils/platform.h"
// ----------------------------------------------------------------------- INCLUDES
#ifdef OST_WINDOWS
	#include <io.h>
#else
	#include <unistd.h>
#endif

#include <fstream>
#include <boost/filesystem.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "utils/namespace.h"
#include "utils/rdotypes.h"
#include "utils/rdomacros.h"
// --------------------------------------------------------------------------------

OPEN_RDO_NAMESPACE

inline rbool File::create(CREF(tstring) name)
{
	return create(name, _T(""));
}

inline rbool File::create(CREF(tstring) name, CREF(tstring) content)
{
	std::ofstream file(name.c_str(), std::ios::out | std::ios::binary);
	file << content.c_str() << std::endl;
	file.close();
	return true;
}

inline rbool File::exist(CREF(tstring) name)
{
	return  boost::filesystem::exists(name.c_str());
}

inline rbool File::read_only(CREF(tstring) name)
{
#ifdef OST_WINDOWS
	return _access(name.c_str(), 04) == 0 && _access(name.c_str(), 06) == -1;
#else  // not OST_WINDOWS
	return access(name.c_str(), R_OK) == 0 && access(name.c_str(), W_OK) == -1;
#endif // OST_WINDOWS
}

inline rbool File::unlink(CREF(tstring) name)
{
	return boost::filesystem::remove(name.c_str());
}

CLOSE_RDO_NAMESPACE
<|endoftext|>


<commit_before>#include "gridpather.h"

#include <QDebug>
#include <QLoggingCategory>
#include <QQuickItem>

#include "passabilityagent.h"
#include "gametimer.h"
#include "gridpathagent.h"
#include "quickentity.h"
#include "steeringagent.h"
#include "utils.h"

Q_LOGGING_CATEGORY(lcGridPather, "quickpather.gridpather")

namespace QuickPather {

GridPathData::GridPathData() :
    mCurrentNodeIndex(-1)
{
}

bool GridPathData::isValid() const
{
    return mCurrentNodeIndex != -1;
}

QPointF GridPathData::targetPos() const
{
    return mTargetPos;
}

QVector<QSharedPointer<GridPathNode> > GridPathData::nodes() const
{
    return mNodes;
}

int GridPathData::currentNodeIndex() const
{
    return mCurrentNodeIndex;
}

GridPather::GridPather(QObject *parent) :
    QObject(parent),
    mCellSize(32),
    mTimer(nullptr),
    mPassabilityAgent(nullptr),
    mSteeringAgent(nullptr)
{
}

static int iterationLimit = 1000;

static const QPointF north(0, -1);
static const QPointF south(0, 1);
static const QPointF east(1, 0);
static const QPointF west(-1, 0);

static const qreal northRotation = 0;
static const qreal southRotation = 180;
static const qreal eastRotation = 90;
static const qreal westRotation = 270;

static const int qtyStraightDirections = 4;

const QPointF straightDirections[qtyStraightDirections] = {
    north, south, east, west
};

/*
   Moves \a entity to \a pos.

   If a path to \a pos was found, any existing movement instructions are removed.
*/
bool GridPather::moveEntityTo(QuickEntity *entity, const QPointF &pos)
{
    if (!entity) {
        qWarning() << "GridPather: entity cannot be null";
        return false;
    }

    if (!mTimer) {
        qWarning() << "GridPather: no timer set";
        return false;
    }

    if (!mPassabilityAgent) {
        qWarning() << "GridPather: no passability agent set";
        return false;
    }

    if (!mSteeringAgent) {
        qWarning() << "GridPather: no steering agent set";
        return false;
    }

    const QPointF startPos = entity->centrePos();
    if (!mPassabilityAgent->isPassable(startPos, entity)) {
        qCDebug(lcGridPather) << "Starting position" << pos << "isn't passable for" << entity;
        return false;
    }

    // TODO: ensure target ends up precisely over node
    const int xDiff = qRound(startPos.x() - mCellSize / 2) % mCellSize;
    const int yDiff = qRound(startPos.y() - mCellSize / 2) % mCellSize;
    if (xDiff != 0 || yDiff != 0) {
        qWarning().nospace() << "GridPather: currently incapable of dealing with non-cell-centered positions ("
            << "the start position " << startPos << " does not result in the entity " << entity << " being centred in a cell)";
        // (Users of this API should simply wait until the target is centered before moving)
        return false;
    }

    QVector<QSharedPointer<GridPathNode> > openList;
    QVector<QSharedPointer<GridPathNode> > closedList;
    QVector<QSharedPointer<GridPathNode> > shortestPath;

    // Starting square is automatically in the open list.
    QSharedPointer<GridPathNode> startNode(new GridPathNode(startPos));
    openList.push_back(startNode);

    // The selected node is the last selected node that was put on the closed list.
    QSharedPointer<GridPathNode> selectedNode;
    int iterations = 0;
    const QPointF nodeDist(mCellSize, mCellSize);
//    const QPointF boundsEnlargement = characterBoundsEnlargement();

    GridPathAgent pathAgent(pos);

    typedef QVector<QSharedPointer<GridPathNode> > NodeVector;
    typedef NodeVector::iterator node_it;
    typedef NodeVector::const_iterator const_node_it;

    do {
        // Look for the lowest "total cost" square on the open list. We refer to this as the selected node.
        node_it lowest = std::min_element(openList.begin(), openList.end(), totalScoreLessThan);
        // Switch it to the closed list.
        closedList.push_back(*lowest);
        onNodeAddedToClosedList((*lowest)->pos());
        selectedNode = *lowest;
        openList.erase(lowest);

        // The search is finished when ...
        if (pathAgent.isPathComplete(*entity, startPos, *selectedNode)) {
            break;
        }

        // For each of the 4 squares adjacent to this current square...
        for(int dirIndex = 0; dirIndex < qtyStraightDirections; ++dirIndex) {
            // Centre of the node.
            const QPointF nodePos(selectedNode->pos() + straightDirections[dirIndex] * nodeDist.x());

            QSharedPointer<GridPathNode> adjNode(new GridPathNode(nodePos));

            bool walkable = mPassabilityAgent->isPassable(adjNode->pos(), entity/*, &boundsEnlargement*/);
            bool isOnClosedList = std::find_if(closedList.begin(), closedList.end(),
                PathNodePosComp(adjNode)) != closedList.end();

            if(walkable && !isOnClosedList) {
                node_it onOpenList = std::find_if(openList.begin(), openList.end(), PathNodePosComp(adjNode));
                bool isOnOpenList = onOpenList != openList.end();

                if(isOnOpenList) {
                    // Check to see if this path to adj_node is better, using "start cost" as the measure.
                    QSharedPointer<GridPathNode> nodeCopy(new GridPathNode(*(*onOpenList)));

                    nodeCopy->setParent(selectedNode);
                    nodeCopy->setStartCost(pathAgent.calculateStartCost(*nodeCopy));
                    nodeCopy->setTargetCost(pathAgent.calculateTargetCost(*nodeCopy));

                    if((*onOpenList)->startCost() < nodeCopy->startCost()) {
                        // Is improved; change its parent to selected.
                        adjNode->setParent(selectedNode);
                        adjNode->setStartCost(pathAgent.calculateStartCost(*adjNode));
                        adjNode->setTargetCost(pathAgent.calculateTargetCost(*adjNode));
                    }
                } else {
                    // Not on open list; add it.
                    adjNode->setParent(selectedNode);
                    adjNode->setStartCost(pathAgent.calculateStartCost(*adjNode));
                    adjNode->setTargetCost(pathAgent.calculateTargetCost(*adjNode));

                    openList.push_back(adjNode);
                    onNodeAddedToOpenList(adjNode->pos());
                }
            }
        }

        ++iterations;
    } while(iterations < iterationLimit && !openList.empty());

    if (iterations == iterationLimit) {
        qWarning() << "iteration limit (" << iterationLimit << ") reached.";
        return false;
    }

    if(closedList.empty()) {
        qCDebug(lcGridPather) << "Impossible for" << entity << "to reach target pos" << pos;
        return false;
    }

    // To get the actual shortest path: working backwards from the target square,
    // we go from each node to its parent node until we reach the starting node.
    QSharedPointer<GridPathNode> node = closedList.back();
    QVector<QSharedPointer<GridPathNode> > test;
    while(node) {
        onNodeChosen(node->pos());

        shortestPath.push_front(node);
        test.insert(test.begin(), node);
        node = node->parent();
    }

    if(!shortestPath.isEmpty()) {
        shortestPath.pop_front();
    }

    GridPathData pathData;
    pathData.mTargetPos = pos;
    pathData.mNodes = shortestPath;
    pathData.mCurrentNodeIndex = 0;
    mData.insert(entity, pathData);

    QObject::connect(entity, &QuickEntity::entityDestroyed, this, &GridPather::cancelEntityMovement);

    qCDebug(lcGridPather) << "Successfully found path (" << shortestPath.size() << "nodes) for" << entity << "to target pos" << pos;
    return true;
}

void GridPather::cancelEntityMovement(QuickEntity *entity)
{
    mData.remove(entity);
    QObject::disconnect(entity, &QuickEntity::entityDestroyed, this, &GridPather::cancelEntityMovement);
}

int GridPather::cellSize() const
{
    return mCellSize;
}

void GridPather::setCellSize(int cellSize)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set cell size while pathing active";
        return;
    }

    if (cellSize == mCellSize)
        return;

    mCellSize = cellSize;
    emit cellSizeChanged();
}

GameTimer *GridPather::timer() const
{
    return mTimer;
}

void GridPather::setTimer(GameTimer *timer)
{
    if (timer == mTimer)
        return;

    if (mTimer)
        mTimer->disconnect(this);

    mTimer = timer;
    emit timerChanged();

    if (mTimer)
        connect(mTimer, &GameTimer::updated, this, &GridPather::timerUpdated);
}

PassabilityAgent *GridPather::passabilityAgent()
{
    return mPassabilityAgent;
}

void GridPather::setPassabilityAgent(PassabilityAgent *passabilityAgent)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set passability agent while pathing active";
        return;
    }

    if (passabilityAgent == mPassabilityAgent)
        return;

    mPassabilityAgent = passabilityAgent;
    emit passabilityAgentChanged();
}

SteeringAgent *GridPather::steeringAgent()
{
    return mSteeringAgent;
}

void GridPather::setSteeringAgent(SteeringAgent *steeringAgent)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set steering agent while pathing active";
        return;
    }

    if (steeringAgent == mSteeringAgent)
        return;

    mSteeringAgent = steeringAgent;
    emit steeringAgentChanged();
}

GridPathData GridPather::pathData(QuickEntity *entity) const
{
    GridPathData data;

    auto dataIt = mData.constFind(entity);
    if (dataIt != mData.constEnd()) {
        data = *dataIt;
    }

    return data;
}

#ifdef EXPOSE_VISUALISATION_API
void GridPather::onNodeAddedToClosedList(const QPointF &centrePos)
{
    emit nodeAddedToClosedList(centrePos);
}

void GridPather::onNodeAddedToOpenList(const QPointF &centrePos)
{
    emit nodeAddedToOpenList(centrePos);
}

void GridPather::onNodeChosen(const QPointF &centrePos)
{
    emit nodeChosen(centrePos);
}
#endif

void GridPather::onCellSizeChanged(int, int)
{
}

void GridPather::timerUpdated(qreal delta)
{
    QHashIterator<QuickEntity*, GridPathData> it(mData);
    while (it.hasNext()) {
        it.next();
        QuickEntity *entity = it.key();

        GridPathData &pathData = mData[entity];
        if (pathData.mCurrentNodeIndex < pathData.mNodes.size()) {
            const GridPathNode currentNode = *pathData.mNodes.at(pathData.mCurrentNodeIndex);
            if (mSteeringAgent->steerTo(entity, currentNode.pos(), delta)) {
                // We've reached the current node.
                ++pathData.mCurrentNodeIndex;
            }
        } else {
            mData.remove(entity);
        }
    }
}

}
<commit_msg>Add debug statement before pathfinding begins to aid profiling<commit_after>#include "gridpather.h"

#include <QDebug>
#include <QLoggingCategory>
#include <QQuickItem>

#include "passabilityagent.h"
#include "gametimer.h"
#include "gridpathagent.h"
#include "quickentity.h"
#include "steeringagent.h"
#include "utils.h"

Q_LOGGING_CATEGORY(lcGridPather, "quickpather.gridpather")

namespace QuickPather {

GridPathData::GridPathData() :
    mCurrentNodeIndex(-1)
{
}

bool GridPathData::isValid() const
{
    return mCurrentNodeIndex != -1;
}

QPointF GridPathData::targetPos() const
{
    return mTargetPos;
}

QVector<QSharedPointer<GridPathNode> > GridPathData::nodes() const
{
    return mNodes;
}

int GridPathData::currentNodeIndex() const
{
    return mCurrentNodeIndex;
}

GridPather::GridPather(QObject *parent) :
    QObject(parent),
    mCellSize(32),
    mTimer(nullptr),
    mPassabilityAgent(nullptr),
    mSteeringAgent(nullptr)
{
}

static int iterationLimit = 1000;

static const QPointF north(0, -1);
static const QPointF south(0, 1);
static const QPointF east(1, 0);
static const QPointF west(-1, 0);

static const qreal northRotation = 0;
static const qreal southRotation = 180;
static const qreal eastRotation = 90;
static const qreal westRotation = 270;

static const int qtyStraightDirections = 4;

const QPointF straightDirections[qtyStraightDirections] = {
    north, south, east, west
};

/*
   Moves \a entity to \a pos.

   If a path to \a pos was found, any existing movement instructions are removed.
*/
bool GridPather::moveEntityTo(QuickEntity *entity, const QPointF &pos)
{
    if (!entity) {
        qWarning() << "GridPather: entity cannot be null";
        return false;
    }

    if (!mTimer) {
        qWarning() << "GridPather: no timer set";
        return false;
    }

    if (!mPassabilityAgent) {
        qWarning() << "GridPather: no passability agent set";
        return false;
    }

    if (!mSteeringAgent) {
        qWarning() << "GridPather: no steering agent set";
        return false;
    }

    const QPointF startPos = entity->centrePos();
    if (!mPassabilityAgent->isPassable(startPos, entity)) {
        qCDebug(lcGridPather) << "Starting position" << pos << "isn't passable for" << entity;
        return false;
    }

    // TODO: ensure target ends up precisely over node
    const int xDiff = qRound(startPos.x() - mCellSize / 2) % mCellSize;
    const int yDiff = qRound(startPos.y() - mCellSize / 2) % mCellSize;
    if (xDiff != 0 || yDiff != 0) {
        qWarning().nospace() << "GridPather: currently incapable of dealing with non-cell-centered positions ("
            << "the start position " << startPos << " does not result in the entity " << entity << " being centred in a cell)";
        // (Users of this API should simply wait until the target is centered before moving)
        return false;
    }

    qCDebug(lcGridPather) << "Looking for path to target pos" << pos;

    QVector<QSharedPointer<GridPathNode> > openList;
    QVector<QSharedPointer<GridPathNode> > closedList;
    QVector<QSharedPointer<GridPathNode> > shortestPath;

    // Starting square is automatically in the open list.
    QSharedPointer<GridPathNode> startNode(new GridPathNode(startPos));
    openList.push_back(startNode);

    // The selected node is the last selected node that was put on the closed list.
    QSharedPointer<GridPathNode> selectedNode;
    int iterations = 0;
    const QPointF nodeDist(mCellSize, mCellSize);
//    const QPointF boundsEnlargement = characterBoundsEnlargement();

    GridPathAgent pathAgent(pos);

    typedef QVector<QSharedPointer<GridPathNode> > NodeVector;
    typedef NodeVector::iterator node_it;
    typedef NodeVector::const_iterator const_node_it;

    do {
        // Look for the lowest "total cost" square on the open list. We refer to this as the selected node.
        node_it lowest = std::min_element(openList.begin(), openList.end(), totalScoreLessThan);
        // Switch it to the closed list.
        closedList.push_back(*lowest);
        onNodeAddedToClosedList((*lowest)->pos());
        selectedNode = *lowest;
        openList.erase(lowest);

        // The search is finished when ...
        if (pathAgent.isPathComplete(*entity, startPos, *selectedNode)) {
            break;
        }

        // For each of the 4 squares adjacent to this current square...
        for(int dirIndex = 0; dirIndex < qtyStraightDirections; ++dirIndex) {
            // Centre of the node.
            const QPointF nodePos(selectedNode->pos() + straightDirections[dirIndex] * nodeDist.x());

            QSharedPointer<GridPathNode> adjNode(new GridPathNode(nodePos));

            bool walkable = mPassabilityAgent->isPassable(adjNode->pos(), entity/*, &boundsEnlargement*/);
            bool isOnClosedList = std::find_if(closedList.begin(), closedList.end(),
                PathNodePosComp(adjNode)) != closedList.end();

            if(walkable && !isOnClosedList) {
                node_it onOpenList = std::find_if(openList.begin(), openList.end(), PathNodePosComp(adjNode));
                bool isOnOpenList = onOpenList != openList.end();

                if(isOnOpenList) {
                    // Check to see if this path to adj_node is better, using "start cost" as the measure.
                    QSharedPointer<GridPathNode> nodeCopy(new GridPathNode(*(*onOpenList)));

                    nodeCopy->setParent(selectedNode);
                    nodeCopy->setStartCost(pathAgent.calculateStartCost(*nodeCopy));
                    nodeCopy->setTargetCost(pathAgent.calculateTargetCost(*nodeCopy));

                    if((*onOpenList)->startCost() < nodeCopy->startCost()) {
                        // Is improved; change its parent to selected.
                        adjNode->setParent(selectedNode);
                        adjNode->setStartCost(pathAgent.calculateStartCost(*adjNode));
                        adjNode->setTargetCost(pathAgent.calculateTargetCost(*adjNode));
                    }
                } else {
                    // Not on open list; add it.
                    adjNode->setParent(selectedNode);
                    adjNode->setStartCost(pathAgent.calculateStartCost(*adjNode));
                    adjNode->setTargetCost(pathAgent.calculateTargetCost(*adjNode));

                    openList.push_back(adjNode);
                    onNodeAddedToOpenList(adjNode->pos());
                }
            }
        }

        ++iterations;
    } while(iterations < iterationLimit && !openList.empty());

    if (iterations == iterationLimit) {
        qWarning() << "iteration limit (" << iterationLimit << ") reached.";
        return false;
    }

    if(closedList.empty()) {
        qCDebug(lcGridPather) << "Impossible for" << entity << "to reach target pos" << pos;
        return false;
    }

    // To get the actual shortest path: working backwards from the target square,
    // we go from each node to its parent node until we reach the starting node.
    QSharedPointer<GridPathNode> node = closedList.back();
    QVector<QSharedPointer<GridPathNode> > test;
    while(node) {
        onNodeChosen(node->pos());

        shortestPath.push_front(node);
        test.insert(test.begin(), node);
        node = node->parent();
    }

    if(!shortestPath.isEmpty()) {
        shortestPath.pop_front();
    }

    GridPathData pathData;
    pathData.mTargetPos = pos;
    pathData.mNodes = shortestPath;
    pathData.mCurrentNodeIndex = 0;
    mData.insert(entity, pathData);

    QObject::connect(entity, &QuickEntity::entityDestroyed, this, &GridPather::cancelEntityMovement);

    qCDebug(lcGridPather) << "Successfully found path (" << shortestPath.size() << "nodes) for" << entity << "to target pos" << pos;
    return true;
}

void GridPather::cancelEntityMovement(QuickEntity *entity)
{
    mData.remove(entity);
    QObject::disconnect(entity, &QuickEntity::entityDestroyed, this, &GridPather::cancelEntityMovement);
}

int GridPather::cellSize() const
{
    return mCellSize;
}

void GridPather::setCellSize(int cellSize)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set cell size while pathing active";
        return;
    }

    if (cellSize == mCellSize)
        return;

    mCellSize = cellSize;
    emit cellSizeChanged();
}

GameTimer *GridPather::timer() const
{
    return mTimer;
}

void GridPather::setTimer(GameTimer *timer)
{
    if (timer == mTimer)
        return;

    if (mTimer)
        mTimer->disconnect(this);

    mTimer = timer;
    emit timerChanged();

    if (mTimer)
        connect(mTimer, &GameTimer::updated, this, &GridPather::timerUpdated);
}

PassabilityAgent *GridPather::passabilityAgent()
{
    return mPassabilityAgent;
}

void GridPather::setPassabilityAgent(PassabilityAgent *passabilityAgent)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set passability agent while pathing active";
        return;
    }

    if (passabilityAgent == mPassabilityAgent)
        return;

    mPassabilityAgent = passabilityAgent;
    emit passabilityAgentChanged();
}

SteeringAgent *GridPather::steeringAgent()
{
    return mSteeringAgent;
}

void GridPather::setSteeringAgent(SteeringAgent *steeringAgent)
{
    if (!mData.isEmpty()) {
        qWarning() << "Cannot set steering agent while pathing active";
        return;
    }

    if (steeringAgent == mSteeringAgent)
        return;

    mSteeringAgent = steeringAgent;
    emit steeringAgentChanged();
}

GridPathData GridPather::pathData(QuickEntity *entity) const
{
    GridPathData data;

    auto dataIt = mData.constFind(entity);
    if (dataIt != mData.constEnd()) {
        data = *dataIt;
    }

    return data;
}

#ifdef EXPOSE_VISUALISATION_API
void GridPather::onNodeAddedToClosedList(const QPointF &centrePos)
{
    emit nodeAddedToClosedList(centrePos);
}

void GridPather::onNodeAddedToOpenList(const QPointF &centrePos)
{
    emit nodeAddedToOpenList(centrePos);
}

void GridPather::onNodeChosen(const QPointF &centrePos)
{
    emit nodeChosen(centrePos);
}
#endif

void GridPather::onCellSizeChanged(int, int)
{
}

void GridPather::timerUpdated(qreal delta)
{
    QHashIterator<QuickEntity*, GridPathData> it(mData);
    while (it.hasNext()) {
        it.next();
        QuickEntity *entity = it.key();

        GridPathData &pathData = mData[entity];
        if (pathData.mCurrentNodeIndex < pathData.mNodes.size()) {
            const GridPathNode currentNode = *pathData.mNodes.at(pathData.mCurrentNodeIndex);
            if (mSteeringAgent->steerTo(entity, currentNode.pos(), delta)) {
                // We've reached the current node.
                ++pathData.mCurrentNodeIndex;
            }
        } else {
            mData.remove(entity);
        }
    }
}

}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016
              Vladimír Vondruš <mosra@centrum.cz>

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

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

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

#include "WindowlessWglApplication.h"

#include <cstring>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>

#include "Magnum/Version.h"
#include "Magnum/Platform/Context.h"

#ifndef DOXYGEN_GENERATING_OUTPUT
/* Define stuff that we need because I can't be bothered with creating a new
   header just for a few defines */
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#endif

namespace Magnum { namespace Platform {

WindowlessWglContext::WindowlessWglContext(const Configuration& configuration, Context* const magnumContext) {
    /* Register the window class (if not yet done) */
    WNDCLASSW wc;
    if(!GetClassInfoW(GetModuleHandleW(nullptr), L"Magnum Windowless Application", &wc)) {
        wc = WNDCLASSW{
            0,
            DefWindowProcW,
            0,
            0,
            GetModuleHandleW(nullptr),
            nullptr,
            nullptr,
            HBRUSH(COLOR_BACKGROUND),
            nullptr,
            L"Magnum Windowless Application"
        };

        if(!RegisterClassW(&wc)) {
            Error() << "Platform::WindowlessWglContext: cannot create window class:" << GetLastError();
            return;
        }
    }

    /* Create the window */
    _window = CreateWindowW(wc.lpszClassName, L"Magnum Windowless Application",
        WS_OVERLAPPEDWINDOW, 0, 0, 32, 32, 0, 0, wc.hInstance, 0);

    /* Get device context */
    const HDC currentDeviceContext = wglGetCurrentDC();
    _deviceContext = GetDC(_window);

    /* Use first provided pixel format  */
    constexpr static const PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        /* Double-buffered with OpenGL support */
        PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,          /* RGBA */
        32,                     /* 32 bit */
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        24,                     /* 24-bit depth buffer */
        8,                      /* 8-bit stencil buffer */
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };
    const int pixelFormat = ChoosePixelFormat(_deviceContext, &pfd);
    SetPixelFormat(_deviceContext, pixelFormat, &pfd);

    /* Create temporary context so we are able to get the pointer to
       wglCreateContextAttribsARB(). To avoid messing up the app state we need
       to save the old active context and then restore it later. */
    const HGLRC currentContext = wglGetCurrentContext();
    const HGLRC temporaryContext = wglCreateContext(_deviceContext);
    if(!wglMakeCurrent(_deviceContext, temporaryContext)) {
        Error() << "Platform::WindowlessWglContext: cannot make temporary context current:" << GetLastError();
        wglDeleteContext(temporaryContext);
        return;
    }

    /* Get pointer to proper context creation function */
    typedef HGLRC(WINAPI*PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
    const PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>( wglGetProcAddress(reinterpret_cast<LPCSTR>("wglCreateContextAttribsARB")));

    /* Optimistically choose core context first */
    const GLint contextAttributes[] = {
        #ifdef MAGNUM_TARGET_GLES
        #ifdef MAGNUM_TARGET_GLES3
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        #elif defined(MAGNUM_TARGET_GLES2)
        WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
        #else
        #error unsupported OpenGL ES version
        #endif
        WGL_CONTEXT_MINOR_VERSION_ARB, 0,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
        WGL_CONTEXT_FLAGS_ARB, GLint(configuration.flags()),
        #else
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 1,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB|GLint(configuration.flags()),
        #endif
        0
    };
    _context = wglCreateContextAttribsARB(_deviceContext, nullptr, contextAttributes);

    #ifndef MAGNUM_TARGET_GLES
    /* Fall back to (forward compatible) GL 2.1 if core context creation fails */
    if(!_context) {
        Warning() << "Platform::WindowlessWglContext: cannot create core context, falling back to compatibility context:" << GetLastError();

        const int fallbackContextAttributes[] = {
            WGL_CONTEXT_FLAGS_ARB, int(configuration.flags()),
            0
        };
        _context = wglCreateContextAttribsARB(_deviceContext, nullptr, fallbackContextAttributes);

    /* Fall back to (forward compatible) GL 2.1 if we are on binary
       NVidia/AMD/Intel drivers on Windows. Instead of creating forward-compatible
       context with highest available version, they force the version to the
       one specified, which is completely useless behavior. */
    } else {
        /* We need to make the context current to read out vendor string */
        if(!wglMakeCurrent(_deviceContext, _context)) {
            Error() << "Platform::WindowlessWglContext: cannot make context current:" << GetLastError();

            /* Everything failed, at least try to delete the dangling contexts
               and revert to the previous context to regain some sanity */
            wglMakeCurrent(_deviceContext, currentContext);
            wglDeleteContext(temporaryContext);
            return;
        }

        /* The workaround check is the last so it doesn't appear in workaround
           list on unrelated drivers */
        constexpr static const char nvidiaVendorString[] = "NVIDIA Corporation";
        constexpr static const char intelVendorString[] = "Intel";
        constexpr static const char amdVendorString[] = "ATI Technologies Inc.";
        const char* const vendorString = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
        if((std::strncmp(vendorString, nvidiaVendorString, sizeof(nvidiaVendorString)) == 0 ||
            std::strncmp(vendorString, intelVendorString, sizeof(intelVendorString)) == 0 ||
            std::strncmp(vendorString, amdVendorString, sizeof(amdVendorString)) == 0) &&
            (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("no-forward-compatible-core-context")))
        {
            /* Destroy the core context and create a compatibility one */
            wglDeleteContext(_context);
            const int fallbackContextAttributes[] = {
                WGL_CONTEXT_FLAGS_ARB, int(configuration.flags()),
                0
            };
            _context = wglCreateContextAttribsARB(_deviceContext, nullptr, fallbackContextAttributes);
        }
    }
    #endif

    /* Make the previous context active and delete the temporary context */
    if(!wglMakeCurrent(currentDeviceContext, currentContext)) {
        Error() << "Platform::WindowlessWglContext: cannot make the previous context current:" << GetLastError();

        /* Everything is fucked up, but try to delete the temporary context
           anyway */
        wglDeleteContext(temporaryContext);
        return;
    }
    wglDeleteContext(temporaryContext);

    if(!_context)
        Error() << "Platform::WindowlessWglContext: cannot create context:" << GetLastError();
}

WindowlessWglContext::WindowlessWglContext(WindowlessWglContext&& other): _window{other._window}, _deviceContext{other._deviceContext}, _context{other._context} {
    other._window = {};
    other._deviceContext = {};
    other._context = {};
}

WindowlessWglContext::~WindowlessWglContext() {
    if(_context) wglDeleteContext(_context);
    if(_window) DestroyWindow(_window);
}

WindowlessWglContext& WindowlessWglContext::operator=(WindowlessWglContext&& other) {
    using std::swap;
    swap(other._window, _window);
    swap(other._deviceContext, _deviceContext);
    swap(other._context, _context);
    return *this;
}

bool WindowlessWglContext::makeCurrent() {
    if(wglMakeCurrent(_deviceContext, _context))
        return true;

    Error() << "Platform::WindowlessWglContext::makeCurrent(): cannot make context current:" << GetLastError();
    return false;
}

#ifndef DOXYGEN_GENERATING_OUTPUT
WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments): WindowlessWglApplication{arguments, Configuration{}} {}
#endif

WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments, const Configuration& configuration): WindowlessWglApplication{arguments, NoCreate} {
    createContext(configuration);
}

WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments, NoCreateT): _glContext{NoCreate}, _context{new Context{NoCreate, arguments.argc, arguments.argv}} {}

void WindowlessWglApplication::createContext() { createContext({}); }

void WindowlessWglApplication::createContext(const Configuration& configuration) {
    if(!tryCreateContext(configuration)) std::exit(1);
}

bool WindowlessWglApplication::tryCreateContext(const Configuration& configuration) {
    CORRADE_ASSERT(_context->version() == Version::None, "Platform::WindowlessWglApplication::tryCreateContext(): context already created", false);

    WindowlessWglContext glContext{configuration, _context.get()};
    if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate())
        return false;

    _glContext = std::move(glContext);
    return true;
}

WindowlessWglApplication::~WindowlessWglApplication() = default;

}}
<commit_msg>Platform: work around horrible wglMakeCurrent() API design.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016
              Vladimír Vondruš <mosra@centrum.cz>

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

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

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

#include "WindowlessWglApplication.h"

#include <cstring>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h>

#include "Magnum/Version.h"
#include "Magnum/Platform/Context.h"

#ifndef DOXYGEN_GENERATING_OUTPUT
/* Define stuff that we need because I can't be bothered with creating a new
   header just for a few defines */
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#endif

namespace Magnum { namespace Platform {

WindowlessWglContext::WindowlessWglContext(const Configuration& configuration, Context* const magnumContext) {
    /* Register the window class (if not yet done) */
    WNDCLASSW wc;
    if(!GetClassInfoW(GetModuleHandleW(nullptr), L"Magnum Windowless Application", &wc)) {
        wc = WNDCLASSW{
            0,
            DefWindowProcW,
            0,
            0,
            GetModuleHandleW(nullptr),
            nullptr,
            nullptr,
            HBRUSH(COLOR_BACKGROUND),
            nullptr,
            L"Magnum Windowless Application"
        };

        if(!RegisterClassW(&wc)) {
            Error() << "Platform::WindowlessWglContext: cannot create window class:" << GetLastError();
            return;
        }
    }

    /* Create the window */
    _window = CreateWindowW(wc.lpszClassName, L"Magnum Windowless Application",
        WS_OVERLAPPEDWINDOW, 0, 0, 32, 32, 0, 0, wc.hInstance, 0);

    /* Get device context from the newly created window and save the previous
       one. In case the previous one is null, wglMakeCurrent(null, ...) would
       fail and thus we need to pass at least something there. As a commenter
       on https://github.com/glfw/glfw/issues/245#issuecomment-43475120 said:
       the Windows API is horrible. HORRIBLE. */
    HDC currentDeviceContext = wglGetCurrentDC();
    _deviceContext = GetDC(_window);
    if(!currentDeviceContext) currentDeviceContext = _deviceContext;

    /* Use first provided pixel format  */
    constexpr static const PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        /* Double-buffered with OpenGL support */
        PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,          /* RGBA */
        32,                     /* 32 bit */
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        24,                     /* 24-bit depth buffer */
        8,                      /* 8-bit stencil buffer */
        0,
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };
    const int pixelFormat = ChoosePixelFormat(_deviceContext, &pfd);
    SetPixelFormat(_deviceContext, pixelFormat, &pfd);

    /* Create temporary context so we are able to get the pointer to
       wglCreateContextAttribsARB(). To avoid messing up the app state we need
       to save the old active context and then restore it later. */
    const HGLRC currentContext = wglGetCurrentContext();
    const HGLRC temporaryContext = wglCreateContext(_deviceContext);
    if(!wglMakeCurrent(_deviceContext, temporaryContext)) {
        Error() << "Platform::WindowlessWglContext: cannot make temporary context current:" << GetLastError();
        wglDeleteContext(temporaryContext);
        return;
    }

    /* Get pointer to proper context creation function */
    typedef HGLRC(WINAPI*PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
    const PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>( wglGetProcAddress(reinterpret_cast<LPCSTR>("wglCreateContextAttribsARB")));

    /* Optimistically choose core context first */
    const GLint contextAttributes[] = {
        #ifdef MAGNUM_TARGET_GLES
        #ifdef MAGNUM_TARGET_GLES3
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        #elif defined(MAGNUM_TARGET_GLES2)
        WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
        #else
        #error unsupported OpenGL ES version
        #endif
        WGL_CONTEXT_MINOR_VERSION_ARB, 0,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
        WGL_CONTEXT_FLAGS_ARB, GLint(configuration.flags()),
        #else
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 1,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB|GLint(configuration.flags()),
        #endif
        0
    };
    _context = wglCreateContextAttribsARB(_deviceContext, nullptr, contextAttributes);

    #ifndef MAGNUM_TARGET_GLES
    /* Fall back to (forward compatible) GL 2.1 if core context creation fails */
    if(!_context) {
        Warning() << "Platform::WindowlessWglContext: cannot create core context, falling back to compatibility context:" << GetLastError();

        const int fallbackContextAttributes[] = {
            WGL_CONTEXT_FLAGS_ARB, int(configuration.flags()),
            0
        };
        _context = wglCreateContextAttribsARB(_deviceContext, nullptr, fallbackContextAttributes);

    /* Fall back to (forward compatible) GL 2.1 if we are on binary
       NVidia/AMD/Intel drivers on Windows. Instead of creating forward-compatible
       context with highest available version, they force the version to the
       one specified, which is completely useless behavior. */
    } else {
        /* We need to make the context current to read out vendor string */
        if(!wglMakeCurrent(_deviceContext, _context)) {
            Error() << "Platform::WindowlessWglContext: cannot make context current:" << GetLastError();

            /* Everything failed, at least try to delete the dangling contexts
               and revert to the previous context to regain some sanity */
            wglMakeCurrent(_deviceContext, currentContext);
            wglDeleteContext(temporaryContext);
            return;
        }

        /* The workaround check is the last so it doesn't appear in workaround
           list on unrelated drivers */
        constexpr static const char nvidiaVendorString[] = "NVIDIA Corporation";
        constexpr static const char intelVendorString[] = "Intel";
        constexpr static const char amdVendorString[] = "ATI Technologies Inc.";
        const char* const vendorString = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
        if((std::strncmp(vendorString, nvidiaVendorString, sizeof(nvidiaVendorString)) == 0 ||
            std::strncmp(vendorString, intelVendorString, sizeof(intelVendorString)) == 0 ||
            std::strncmp(vendorString, amdVendorString, sizeof(amdVendorString)) == 0) &&
            (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("no-forward-compatible-core-context")))
        {
            /* Destroy the core context and create a compatibility one */
            wglDeleteContext(_context);
            const int fallbackContextAttributes[] = {
                WGL_CONTEXT_FLAGS_ARB, int(configuration.flags()),
                0
            };
            _context = wglCreateContextAttribsARB(_deviceContext, nullptr, fallbackContextAttributes);
        }
    }
    #endif

    /* Make the previous context active and delete the temporary context */
    if(!wglMakeCurrent(currentDeviceContext, currentContext)) {
        Error() << "Platform::WindowlessWglContext: cannot make the previous context current:" << GetLastError();

        /* Everything is fucked up, but try to delete the temporary context
           anyway */
        wglDeleteContext(temporaryContext);
        return;
    }
    wglDeleteContext(temporaryContext);

    if(!_context)
        Error() << "Platform::WindowlessWglContext: cannot create context:" << GetLastError();
}

WindowlessWglContext::WindowlessWglContext(WindowlessWglContext&& other): _window{other._window}, _deviceContext{other._deviceContext}, _context{other._context} {
    other._window = {};
    other._deviceContext = {};
    other._context = {};
}

WindowlessWglContext::~WindowlessWglContext() {
    if(_context) wglDeleteContext(_context);
    if(_window) DestroyWindow(_window);
}

WindowlessWglContext& WindowlessWglContext::operator=(WindowlessWglContext&& other) {
    using std::swap;
    swap(other._window, _window);
    swap(other._deviceContext, _deviceContext);
    swap(other._context, _context);
    return *this;
}

bool WindowlessWglContext::makeCurrent() {
    if(wglMakeCurrent(_deviceContext, _context))
        return true;

    Error() << "Platform::WindowlessWglContext::makeCurrent(): cannot make context current:" << GetLastError();
    return false;
}

#ifndef DOXYGEN_GENERATING_OUTPUT
WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments): WindowlessWglApplication{arguments, Configuration{}} {}
#endif

WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments, const Configuration& configuration): WindowlessWglApplication{arguments, NoCreate} {
    createContext(configuration);
}

WindowlessWglApplication::WindowlessWglApplication(const Arguments& arguments, NoCreateT): _glContext{NoCreate}, _context{new Context{NoCreate, arguments.argc, arguments.argv}} {}

void WindowlessWglApplication::createContext() { createContext({}); }

void WindowlessWglApplication::createContext(const Configuration& configuration) {
    if(!tryCreateContext(configuration)) std::exit(1);
}

bool WindowlessWglApplication::tryCreateContext(const Configuration& configuration) {
    CORRADE_ASSERT(_context->version() == Version::None, "Platform::WindowlessWglApplication::tryCreateContext(): context already created", false);

    WindowlessWglContext glContext{configuration, _context.get()};
    if(!glContext.isCreated() || !glContext.makeCurrent() || !_context->tryCreate())
        return false;

    _glContext = std::move(glContext);
    return true;
}

WindowlessWglApplication::~WindowlessWglApplication() = default;

}}
<|endoftext|>


<commit_before>//===-- DeadObjectElimination.h - Remove unused objects  ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates store only alloc_ref objects that have destructors
// without side effects.
//
// The high level overview of the algorithm is that first it visits the
// destructor and attempts to prove that the destructor is well behaved, i.e. it
// does not have any side effects outside of the destructor itself. If the
// destructor can be proven to be well behaved, it then goes through the use
// list of the alloc_ref and attempts to prove that the alloc_ref does not
// escape or is used in a way that could cause side effects. If both of those
// conditions apply, the alloc_ref and its entire use graph is eliminated.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "allocref-elim"
#include "swift/SILPasses/Passes.h"
#include "swift/AST/ResilienceExpansion.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumStoreOnlyAllocRefEliminated,
          "number of store only alloc ref eliminated.");

//===----------------------------------------------------------------------===//
//                            Destructor Analysis
//===----------------------------------------------------------------------===//

/// Analyze the destructor for the class of ARI to see if any instructions in it
/// could have side effects on the program outside the destructor. If it does
/// not, then we can eliminate the destructor.
static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) {
  // We only support classes. Assume all other cases have side effects.
  ClassDecl *ClsDecl = ARI->getType().getClassOrBoundGenericClass();
  if (!ClsDecl)
    return true;

  // Look up the destructor of ClsDecl.
  DestructorDecl *Destructor = ClsDecl->getDestructor();
  assert(Destructor && "getDestructor() should never return a nullptr.");

  // Ok we have a destructor. Compute its name (our lookup key) via SILDeclRef.
  //
  // FIXME: When destructors get moved into vtables, update this to use the
  // vtable for the class.
  SmallVector<char, 128> buffer;
  StringRef Name = SILDeclRef(Destructor).mangle(buffer,
                                                 ResilienceExpansion::Minimal);
  DEBUG(llvm::dbgs() << "    Looking up destructor: " << Name << "\n");

  // Then try to lookup the destructor from the module. If we can't the
  // destructor is unable to be found or external, be conservative and assume
  // that it does have side effects.
  SILFunction *Fn = ARI->getModule().lookUpFunction(Name);
  if (!Fn || Fn->empty()) {
    DEBUG(llvm::dbgs() << "    Could not find destructor...\n");
    return true;
  }

  DEBUG(llvm::dbgs() << "    Found destructor!\n");

  // If the destructor has an objc_method calling convention, we can not analyze
  // it since it could be swapped out from under us at runtime.
  if (Fn->getAbstractCC() == AbstractCC::ObjCMethod) {
    DEBUG(llvm::dbgs() << "        Found objective-c destructor. Can't "
          "analyze!\n");
    return true;
  }

  // A destructor only has one argument, self.
  assert(Fn->begin()->getNumBBArg() == 1 &&
         "Destructor should have only one argument, self.");
  SILArgument *Self = Fn->begin()->getBBArg(0);

  DEBUG(llvm::dbgs() << "    Analyzing destructor.\n");

  // For each BB in the destructor...
  for (auto &BB : *Fn)
    // For each instruction I in BB...
    for (auto &I : BB) {
      DEBUG(llvm::dbgs() << "        Visiting: " << I);

      // If I has no side effects, we can ignore it.
      if (!I.mayHaveSideEffects()) {
        DEBUG(llvm::dbgs() << "            SAFE! Instruction has no side "
              "effects.\n");
        continue;
      }

      // RefCounting operations on Self are ok since we are already in the
      // destructor. RefCountingOperations on other instructions could have side
      // effects though.
      if (auto *RefInst = dyn_cast<RefCountingInst>(&I)) {
        if (RefInst->getOperand(0).stripCasts().getDef() == Self) {
          // For now all ref counting insts have 1 operand. Put in an assert
          // just in case.
          assert(RefInst->getNumOperands() == 1 &&
                 "Make sure RefInst only has one argument.");
          DEBUG(llvm::dbgs() << "            SAFE! Ref count operation on "
                "Self.\n");
          continue;
        } else {
          DEBUG(llvm::dbgs() << "            UNSAFE! Ref count operation not on"
                " self.\n");
          return true;
        }
      }

      // dealloc_stack can be ignored.
      if (isa<DeallocStackInst>(I)) {
        DEBUG(llvm::dbgs() << "            SAFE! dealloc_stack can be "
              "ignored.\n");
        continue;
      }

      // dealloc_ref on self can be ignored, but dealloc_ref on anything else
      // can not be eliminated.
      if (auto *DeallocRef = dyn_cast<DeallocRefInst>(&I)) {
        if (DeallocRef->getOperand().stripCasts().getDef() == Self) {
          DEBUG(llvm::dbgs() << "            SAFE! dealloc_ref on self.\n");
          continue;
        } else {
          DEBUG(llvm::dbgs() << "            UNSAFE! dealloc_ref on value "
                "besides self.\n");
          return true;
        }
      }

      // If I is an apply calling a builtin that does not have side effects, we
      // can ignore it.
      if (auto *AI = dyn_cast<ApplyInst>(&I))
        if (auto *FR = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
          if (isSideEffectFree(FR)) {
            DEBUG(llvm::dbgs() << "            SAFE! No side effect "
                  "builtin.\n");
            continue;
          }

      // Storing into the object can be ignored.
      if (auto *SI = dyn_cast<StoreInst>(&I))
        if (SI->getDest().stripAddressProjections().getDef() == Self) {
          DEBUG(llvm::dbgs() << "            SAFE! Instruction is a store into "
                "self.\n");
          continue;
        }

      DEBUG(llvm::dbgs() << "            UNSAFE! Unknown instruction.\n");
      // Otherwise, we can't remove the deallocation completely.
      return true;
    }

  // We didn't find any side effects.
  return false;
}

//===----------------------------------------------------------------------===//
//                             Use Graph Analysis
//===----------------------------------------------------------------------===//

/// Returns true if Inst is an instruction that would require us to keep the
/// alloc_ref alive.
static bool canZapInstruction(SILInstruction *Inst) {
  // It is ok to eliminate various retains/releases. We are either removing
  // everything or nothing.
  if (isa<RefCountingInst>(Inst))
    return true;

  // If we see a store here, we have already checked that we are storing into
  // the pointer before we added it to the worklist, so we can skip it.
  if (isa<StoreInst>(Inst))
    return true;

  // If Inst does not read or write to memory, have side effects, and is not a
  // terminator, we can zap it.
  if (Inst->getMemoryBehavior() == SILInstruction::MemoryBehavior::None &&
      !isa<TermInst>(Inst))
    return true;

  // Otherwise we do not know how to handle this instruction. Be conservative
  // and don't zap it.
  return false;
}

/// Analyze the use graph of AllocRef for any uses that would prevent us from
/// zapping it completely.
static bool
hasUnremoveableUsers(SILInstruction *AllocRef,
                llvm::SmallSetVector<SILInstruction *, 16> &Users) {
  SmallVector<SILInstruction *, 16> Worklist;
  Worklist.push_back(AllocRef);

  DEBUG(llvm::dbgs() << "    Analyzing Use Graph.");

  while (!Worklist.empty()) {
    SILInstruction *I = Worklist.pop_back_val();

    DEBUG(llvm::dbgs() << "        Visiting: " << *I);

    // Insert the instruction into our InvolvedInstructions set.  If we have
    // already seen it, then don't reprocess all of the uses.
    if (!Users.insert(I)) {
      DEBUG(llvm::dbgs() << "        Already seen skipping...\n");
      continue;
    }

    // If we can't zap this instruction... bail...
    if (!canZapInstruction(I)) {
      DEBUG(llvm::dbgs() << "        Found instruction we can't zap...\n");
      return false;
    }

    // At this point, we can remove the instruction as long as all of its users
    // can be removed as well. Scan its users and add them to the worklist for
    // recursive processing.
    for (auto *Op : I->getUses()) {
      auto *User = Op->getUser();

      // Make sure that we are only storing into our users, not storing our
      // users which would be an escape.
      if (auto *SI = dyn_cast<StoreInst>(User))
        if (Op->get() == SI->getSrc()) {
          DEBUG(llvm::dbgs() << "        Found store of pointer. Failure: " <<
                *SI);
          return false;
        }

      // Otherwise, add normal instructions to the worklist for processing.
      Worklist.push_back(User);
    }
  }

  return true;
}

class DeadObjectElimination : public SILFunctionTransform {
  llvm::DenseMap<SILType, bool> DestructorAnalysisCache;

  bool processFunction(SILFunction &Fn);

  void run() {
    if (processFunction(*getFunction()))
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "AllocRef Elimination"; }
};

//===----------------------------------------------------------------------===//
//                            Function Processing
//===----------------------------------------------------------------------===//

bool DeadObjectElimination::processFunction(SILFunction &Fn) {
  DEBUG(llvm::dbgs() << "***** Processing Function " << Fn.getName()
        << " *****\n");

  llvm::SmallVector<SILInstruction *, 16> DeleteList;
  bool Changed = false;

  // For each BB in Fn...
  for (auto &BB : Fn)

    // For each inst in BB...
    for (auto II = BB.begin(), IE = BB.end(); II != IE;) {

      // If the inst is not an alloc_ref inst, skip it...
      auto *AllocRef = dyn_cast<AllocRefInst>(II);
      if (!AllocRef) {
        ++II;
        continue;
      }

      DEBUG(llvm::dbgs() << "Visiting: " << *AllocRef);

      // Ok, we have an alloc_ref. Check the cache to see if we have already
      // computed the destructor behavior for its SILType.
      bool HasSideEffects;
      SILType Type = AllocRef->getType();
      auto CacheSearchResult = DestructorAnalysisCache.find(Type);
      if (CacheSearchResult != DestructorAnalysisCache.end()) {
        // Ok we found a value in the cache.
        HasSideEffects = CacheSearchResult->second;
      } else {
        // We did not find a value in the cache for our destructor. Analyze the
        // destructor to make sure it has no side effects. For now this only
        // supports alloc_ref of classes so any alloc_ref with a reference type
        // that is not a class this will return false for. Once we have analyzed
        // it, set Behavior to that value and insert the value into the Cache.
        HasSideEffects = doesDestructorHaveSideEffects(AllocRef);
        DestructorAnalysisCache[Type] = HasSideEffects;
      }

      if (HasSideEffects) {
        DEBUG(llvm::dbgs() << "    Destructor had side effects. Can't "
              "eliminate alloc_ref\n");
        ++II;
        continue;
      }

      // Our destructor has no side effects, so if we can prove no loads or
      // escapes, then we can completely remove the use graph of this alloc_ref.
      llvm::SmallSetVector<SILInstruction *, 16> UsersToRemove;
      if (!hasUnremoveableUsers(AllocRef, UsersToRemove)) {
        DEBUG(llvm::dbgs() << "    Found a use that can not be zapped...\n");
        ++II;
        continue;
      }

      // Ok, we succeeded! Add all of the involved instructions to our delete
      // list.
      for (auto *I : UsersToRemove)
        DeleteList.push_back(I);
      DEBUG(llvm::dbgs() << "    Success! Eliminating alloc_ref.\n");

      ++NumStoreOnlyAllocRefEliminated;
      ++II;
      Changed = true;
    }

  // Erase all instructions that are in DeleteList.
  for (auto *I : DeleteList) {
    // If I has any uses left, just set them to be undef.
    if (!I->use_empty())
      for (unsigned i = 0, e = I->getNumTypes(); i != e; ++i)
        SILValue(I, i).replaceAllUsesWith(SILUndef::get(I->getType(i),
                                                        I->getModule()));
    // Now we know that I should not have any uses... erase it from its parent.
    I->eraseFromParent();
  }
  return Changed;
}

//===----------------------------------------------------------------------===//
//                              Top Level Driver
//===----------------------------------------------------------------------===//

SILTransform *swift::createDeadObjectElimination() {
  return new DeadObjectElimination();
}
<commit_msg>Refactor the code for finding the destructor.<commit_after>//===-- DeadObjectElimination.h - Remove unused objects  ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates store only alloc_ref objects that have destructors
// without side effects.
//
// The high level overview of the algorithm is that first it visits the
// destructor and attempts to prove that the destructor is well behaved, i.e. it
// does not have any side effects outside of the destructor itself. If the
// destructor can be proven to be well behaved, it then goes through the use
// list of the alloc_ref and attempts to prove that the alloc_ref does not
// escape or is used in a way that could cause side effects. If both of those
// conditions apply, the alloc_ref and its entire use graph is eliminated.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "allocref-elim"
#include "swift/SILPasses/Passes.h"
#include "swift/AST/ResilienceExpansion.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumStoreOnlyAllocRefEliminated,
          "number of store only alloc ref eliminated.");

//===----------------------------------------------------------------------===//
//                            Destructor Analysis
//===----------------------------------------------------------------------===//

static SILFunction *getDestructor(AllocationInst* AI) {
  if (auto *ARI = dyn_cast<AllocRefInst>(AI)) {
    // We only support classes.
    ClassDecl *ClsDecl = ARI->getType().getClassOrBoundGenericClass();
    if (!ClsDecl)
      return nullptr;

    // Look up the destructor of ClsDecl.
    DestructorDecl *Destructor = ClsDecl->getDestructor();
    assert(Destructor && "getDestructor() should never return a nullptr.");

    // Find the destructor name via SILDeclRef.
    // FIXME: When destructors get moved into vtables, update this to use the
    // vtable for the class.
    SmallVector<char, 128> buffer;
    StringRef Name = SILDeclRef(Destructor).mangle(buffer,
                                                  ResilienceExpansion::Minimal);
    DEBUG(llvm::dbgs() << "    Looking up destructor: " << Name << "\n");

    // Then try to lookup the destructor from the module.
    SILFunction *Fn = ARI->getModule().lookUpFunction(Name);
    if (!Fn || Fn->empty()) {
      DEBUG(llvm::dbgs() << "    Could not find destructor.\n");
      return nullptr;
    }

    DEBUG(llvm::dbgs() << "    Found destructor!\n");

    // If the destructor has an objc_method calling convention, we can not
    // analyze it since it could be swapped out from under us at runtime.
    if (Fn->getAbstractCC() == AbstractCC::ObjCMethod) {
      DEBUG(llvm::dbgs() << "        Found objective-c destructor. Can't "
            "analyze!\n");
      return nullptr;
    }

    return Fn;
  }

  return nullptr;
}

/// Analyze the destructor for the class of ARI to see if any instructions in it
/// could have side effects on the program outside the destructor. If it does
/// not, then we can eliminate the destructor.
static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) {
  SILFunction *Fn = getDestructor(ARI);
  // If we can't find a constructor then assume it has side effects.
  if (!Fn)
    return true;

  // A destructor only has one argument, self.
  assert(Fn->begin()->getNumBBArg() == 1 &&
         "Destructor should have only one argument, self.");
  SILArgument *Self = Fn->begin()->getBBArg(0);

  DEBUG(llvm::dbgs() << "    Analyzing destructor.\n");

  // For each BB in the destructor...
  for (auto &BB : *Fn)
    // For each instruction I in BB...
    for (auto &I : BB) {
      DEBUG(llvm::dbgs() << "        Visiting: " << I);

      // If I has no side effects, we can ignore it.
      if (!I.mayHaveSideEffects()) {
        DEBUG(llvm::dbgs() << "            SAFE! Instruction has no side "
              "effects.\n");
        continue;
      }

      // RefCounting operations on Self are ok since we are already in the
      // destructor. RefCountingOperations on other instructions could have side
      // effects though.
      if (auto *RefInst = dyn_cast<RefCountingInst>(&I)) {
        if (RefInst->getOperand(0).stripCasts().getDef() == Self) {
          // For now all ref counting insts have 1 operand. Put in an assert
          // just in case.
          assert(RefInst->getNumOperands() == 1 &&
                 "Make sure RefInst only has one argument.");
          DEBUG(llvm::dbgs() << "            SAFE! Ref count operation on "
                "Self.\n");
          continue;
        } else {
          DEBUG(llvm::dbgs() << "            UNSAFE! Ref count operation not on"
                " self.\n");
          return true;
        }
      }

      // dealloc_stack can be ignored.
      if (isa<DeallocStackInst>(I)) {
        DEBUG(llvm::dbgs() << "            SAFE! dealloc_stack can be "
              "ignored.\n");
        continue;
      }

      // dealloc_ref on self can be ignored, but dealloc_ref on anything else
      // can not be eliminated.
      if (auto *DeallocRef = dyn_cast<DeallocRefInst>(&I)) {
        if (DeallocRef->getOperand().stripCasts().getDef() == Self) {
          DEBUG(llvm::dbgs() << "            SAFE! dealloc_ref on self.\n");
          continue;
        } else {
          DEBUG(llvm::dbgs() << "            UNSAFE! dealloc_ref on value "
                "besides self.\n");
          return true;
        }
      }

      // If I is an apply calling a builtin that does not have side effects, we
      // can ignore it.
      if (auto *AI = dyn_cast<ApplyInst>(&I))
        if (auto *FR = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
          if (isSideEffectFree(FR)) {
            DEBUG(llvm::dbgs() << "            SAFE! No side effect "
                  "builtin.\n");
            continue;
          }

      // Storing into the object can be ignored.
      if (auto *SI = dyn_cast<StoreInst>(&I))
        if (SI->getDest().stripAddressProjections().getDef() == Self) {
          DEBUG(llvm::dbgs() << "            SAFE! Instruction is a store into "
                "self.\n");
          continue;
        }

      DEBUG(llvm::dbgs() << "            UNSAFE! Unknown instruction.\n");
      // Otherwise, we can't remove the deallocation completely.
      return true;
    }

  // We didn't find any side effects.
  return false;
}

//===----------------------------------------------------------------------===//
//                             Use Graph Analysis
//===----------------------------------------------------------------------===//

/// Returns true if Inst is an instruction that would require us to keep the
/// alloc_ref alive.
static bool canZapInstruction(SILInstruction *Inst) {
  // It is ok to eliminate various retains/releases. We are either removing
  // everything or nothing.
  if (isa<RefCountingInst>(Inst))
    return true;

  // If we see a store here, we have already checked that we are storing into
  // the pointer before we added it to the worklist, so we can skip it.
  if (isa<StoreInst>(Inst))
    return true;

  // If Inst does not read or write to memory, have side effects, and is not a
  // terminator, we can zap it.
  if (Inst->getMemoryBehavior() == SILInstruction::MemoryBehavior::None &&
      !isa<TermInst>(Inst))
    return true;

  // Otherwise we do not know how to handle this instruction. Be conservative
  // and don't zap it.
  return false;
}

/// Analyze the use graph of AllocRef for any uses that would prevent us from
/// zapping it completely.
static bool
hasUnremoveableUsers(SILInstruction *AllocRef,
                llvm::SmallSetVector<SILInstruction *, 16> &Users) {
  SmallVector<SILInstruction *, 16> Worklist;
  Worklist.push_back(AllocRef);

  DEBUG(llvm::dbgs() << "    Analyzing Use Graph.");

  while (!Worklist.empty()) {
    SILInstruction *I = Worklist.pop_back_val();

    DEBUG(llvm::dbgs() << "        Visiting: " << *I);

    // Insert the instruction into our InvolvedInstructions set.  If we have
    // already seen it, then don't reprocess all of the uses.
    if (!Users.insert(I)) {
      DEBUG(llvm::dbgs() << "        Already seen skipping...\n");
      continue;
    }

    // If we can't zap this instruction... bail...
    if (!canZapInstruction(I)) {
      DEBUG(llvm::dbgs() << "        Found instruction we can't zap...\n");
      return false;
    }

    // At this point, we can remove the instruction as long as all of its users
    // can be removed as well. Scan its users and add them to the worklist for
    // recursive processing.
    for (auto *Op : I->getUses()) {
      auto *User = Op->getUser();

      // Make sure that we are only storing into our users, not storing our
      // users which would be an escape.
      if (auto *SI = dyn_cast<StoreInst>(User))
        if (Op->get() == SI->getSrc()) {
          DEBUG(llvm::dbgs() << "        Found store of pointer. Failure: " <<
                *SI);
          return false;
        }

      // Otherwise, add normal instructions to the worklist for processing.
      Worklist.push_back(User);
    }
  }

  return true;
}

class DeadObjectElimination : public SILFunctionTransform {
  llvm::DenseMap<SILType, bool> DestructorAnalysisCache;

  bool processFunction(SILFunction &Fn);

  void run() {
    if (processFunction(*getFunction()))
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "AllocRef Elimination"; }
};

//===----------------------------------------------------------------------===//
//                            Function Processing
//===----------------------------------------------------------------------===//

bool DeadObjectElimination::processFunction(SILFunction &Fn) {
  DEBUG(llvm::dbgs() << "***** Processing Function " << Fn.getName()
        << " *****\n");

  llvm::SmallVector<SILInstruction *, 16> DeleteList;
  bool Changed = false;

  // For each BB in Fn...
  for (auto &BB : Fn)

    // For each inst in BB...
    for (auto II = BB.begin(), IE = BB.end(); II != IE;) {

      // If the inst is not an alloc_ref inst, skip it...
      auto *AllocRef = dyn_cast<AllocRefInst>(II);
      if (!AllocRef) {
        ++II;
        continue;
      }

      DEBUG(llvm::dbgs() << "Visiting: " << *AllocRef);

      // Ok, we have an alloc_ref. Check the cache to see if we have already
      // computed the destructor behavior for its SILType.
      bool HasSideEffects;
      SILType Type = AllocRef->getType();
      auto CacheSearchResult = DestructorAnalysisCache.find(Type);
      if (CacheSearchResult != DestructorAnalysisCache.end()) {
        // Ok we found a value in the cache.
        HasSideEffects = CacheSearchResult->second;
      } else {
        // We did not find a value in the cache for our destructor. Analyze the
        // destructor to make sure it has no side effects. For now this only
        // supports alloc_ref of classes so any alloc_ref with a reference type
        // that is not a class this will return false for. Once we have analyzed
        // it, set Behavior to that value and insert the value into the Cache.
        HasSideEffects = doesDestructorHaveSideEffects(AllocRef);
        DestructorAnalysisCache[Type] = HasSideEffects;
      }

      if (HasSideEffects) {
        DEBUG(llvm::dbgs() << "    Destructor had side effects. Can't "
              "eliminate alloc_ref\n");
        ++II;
        continue;
      }

      // Our destructor has no side effects, so if we can prove no loads or
      // escapes, then we can completely remove the use graph of this alloc_ref.
      llvm::SmallSetVector<SILInstruction *, 16> UsersToRemove;
      if (!hasUnremoveableUsers(AllocRef, UsersToRemove)) {
        DEBUG(llvm::dbgs() << "    Found a use that can not be zapped...\n");
        ++II;
        continue;
      }

      // Ok, we succeeded! Add all of the involved instructions to our delete
      // list.
      for (auto *I : UsersToRemove)
        DeleteList.push_back(I);
      DEBUG(llvm::dbgs() << "    Success! Eliminating alloc_ref.\n");

      ++NumStoreOnlyAllocRefEliminated;
      ++II;
      Changed = true;
    }

  // Erase all instructions that are in DeleteList.
  for (auto *I : DeleteList) {
    // If I has any uses left, just set them to be undef.
    if (!I->use_empty())
      for (unsigned i = 0, e = I->getNumTypes(); i != e; ++i)
        SILValue(I, i).replaceAllUsesWith(SILUndef::get(I->getType(i),
                                                        I->getModule()));
    // Now we know that I should not have any uses... erase it from its parent.
    I->eraseFromParent();
  }
  return Changed;
}

//===----------------------------------------------------------------------===//
//                              Top Level Driver
//===----------------------------------------------------------------------===//

SILTransform *swift::createDeadObjectElimination() {
  return new DeadObjectElimination();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Deflater.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 16:11:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _DEFLATER_HXX_
#include <Deflater.hxx>
#endif
#ifndef _ZLIB_H
#ifdef SYSTEM_ZLIB
#include <zlib.h>
#else
#include <external/zlib/zlib.h>
#endif
#endif
#ifndef _VOS_DIAGNOSE_H_
#include <vos/diagnose.hxx>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIP_ZIPCONSTANTS_HPP_
#include <com/sun/star/packages/zip/ZipConstants.hpp>
#endif
#include <string.h> // for memset

using namespace com::sun::star::packages::zip::ZipConstants;
using namespace com::sun::star;

/** Provides general purpose compression using the ZLIB compression
 * library.
 */

Deflater::~Deflater(void)
{
    end();
}
void Deflater::init (sal_Int32 nLevel, sal_Int32 nStrategy, sal_Bool bNowrap)
{
    pStream = new z_stream;
    /* Memset it to 0...sets zalloc/zfree/opaque to NULL */
    memset (pStream, 0, sizeof(*pStream));

    switch (deflateInit2(pStream, nLevel, Z_DEFLATED, bNowrap? -MAX_WBITS : MAX_WBITS,
                DEF_MEM_LEVEL, nStrategy))
    {
        case Z_OK:
            break;
        case Z_MEM_ERROR:
            delete pStream;
            break;
        case Z_STREAM_ERROR:
            delete pStream;
            break;
        default:
             break;
    }
}
Deflater::Deflater()
: nLevel(DEFAULT_COMPRESSION)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(DEFAULT_COMPRESSION, DEFAULT_STRATEGY, sal_False);
}

Deflater::Deflater(sal_Int32 nSetLevel)
: nLevel(nSetLevel)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(nSetLevel, DEFAULT_STRATEGY, sal_False);
}

Deflater::Deflater(sal_Int32 nSetLevel, sal_Bool bNowrap)
: nLevel(nSetLevel)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(nSetLevel, DEFAULT_STRATEGY, bNowrap);
}

sal_Int32 Deflater::doDeflateBytes (uno::Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength)
{
    sal_Int32 nResult;
    if (bSetParams)
    {
        pStream->next_in   = (unsigned char*) sInBuffer.getConstArray();
        pStream->next_out  = (unsigned char*) rBuffer.getArray()+nNewOffset;
        pStream->avail_in  = nLength;
        pStream->avail_out = nNewLength;

#ifdef SYSTEM_ZLIB
        nResult = deflateParams(pStream, nLevel, nStrategy);
#else
        nResult = z_deflateParams(pStream, nLevel, nStrategy);
#endif
        switch (nResult)
        {
            case Z_OK:
                bSetParams = sal_False;
                nOffset += nLength - pStream->avail_in;
                nLength = pStream->avail_in;
                return nNewLength - pStream->avail_out;
            case Z_BUF_ERROR:
                bSetParams = sal_False;
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
            default:
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
        }
    }
    else
    {
        pStream->next_in   = (unsigned char*) sInBuffer.getConstArray();
        pStream->next_out  = (unsigned char*) rBuffer.getArray()+nNewOffset;
        pStream->avail_in  = nLength;
        pStream->avail_out = nNewLength;

#ifdef SYSTEM_ZLIB
        nResult = deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH);
#else
        nResult = z_deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH);
#endif
        switch (nResult)
        {
            case Z_STREAM_END:
                bFinished = sal_True;
            case Z_OK:
                nOffset += nLength - pStream->avail_in;
                nLength = pStream->avail_in;
                return nNewLength - pStream->avail_out;
            case Z_BUF_ERROR:
                bSetParams = sal_False;
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
            default:
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
        }
    }
}

void SAL_CALL Deflater::setInputSegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
        VOS_DEBUG_ONLY("Invalid parameters to Deflater::setInputSegment!");

    sInBuffer = rBuffer;
    nOffset = nNewOffset;
    nLength = nNewLength;
}
void SAL_CALL Deflater::setInput( const uno::Sequence< sal_Int8 >& rBuffer )
{
    sInBuffer = rBuffer;
    nOffset = 0;
    nLength = rBuffer.getLength();
}
void SAL_CALL Deflater::setDictionarySegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (pStream == NULL)
    {
        // do error handling
        VOS_DEBUG_ONLY("No stream!");
    }
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
    {
        // do error handling
    }
#ifdef SYSTEM_ZLIB
    sal_Int32 nResult = deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray()+nOffset, nLength);
#else
    sal_Int32 nResult = z_deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray()+nOffset, nLength);
#endif
}
void SAL_CALL Deflater::setDictionary( const uno::Sequence< sal_Int8 >& rBuffer )
{
    if (pStream == NULL)
    {
        // do error handling
        VOS_DEBUG_ONLY("No stream!");

    }
#ifdef SYSTEM_ZLIB
    sal_Int32 nResult = deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray(), rBuffer.getLength());
#else
    sal_Int32 nResult = z_deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray(), rBuffer.getLength());
#endif
}
void SAL_CALL Deflater::setStrategy( sal_Int32 nNewStrategy )
{
    if (nNewStrategy != DEFAULT_STRATEGY &&
        nNewStrategy != FILTERED &&
        nNewStrategy != HUFFMAN_ONLY)
    {
        // do error handling
    }
    if (nStrategy != nNewStrategy)
    {
        nStrategy = nNewStrategy;
        bSetParams = sal_True;
    }
}
void SAL_CALL Deflater::setLevel( sal_Int32 nNewLevel )
{
    if ((nNewLevel < 0 || nNewLevel > 9) && nNewLevel != DEFAULT_COMPRESSION)
    {
        // do error handling
    }
    if (nNewLevel != nLevel)
    {
        nLevel = nNewLevel;
        bSetParams = sal_True;
    }
}
sal_Bool SAL_CALL Deflater::needsInput(  )
{
    return nLength <=0;
}
void SAL_CALL Deflater::finish(  )
{
    bFinish = sal_True;
}
sal_Bool SAL_CALL Deflater::finished(  )
{
    return bFinished;
}
sal_Int32 SAL_CALL Deflater::doDeflateSegment( uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
        VOS_DEBUG_ONLY("Invalid Offset or Length passed to doDeflateSegment");
    return doDeflateBytes(rBuffer, nNewOffset, nNewLength);
}
sal_Int32 SAL_CALL Deflater::doDeflate( uno::Sequence< sal_Int8 >& rBuffer )
{
    return doDeflateBytes(rBuffer, 0, rBuffer.getLength());
}

sal_Int32 SAL_CALL Deflater::getAdler(  )
{
    return pStream->adler;
}
sal_Int32 SAL_CALL Deflater::getTotalIn(  )
{
    return pStream->total_in;
}
sal_Int32 SAL_CALL Deflater::getTotalOut(  )
{
    return pStream->total_out;
}
void SAL_CALL Deflater::reset(  )
{
#ifdef SYSTEM_ZLIB
    deflateReset(pStream);
#else
    z_deflateReset(pStream);
#endif
    bFinish = sal_False;
    bFinished = sal_False;
    nOffset = nLength = 0;
}
void SAL_CALL Deflater::end(  )
{
    if (pStream != NULL)
    {
#ifdef SYSTEM_ZLIB
        deflateEnd(pStream);
#else
        z_deflateEnd(pStream);
#endif
        delete pStream;
    }
    pStream = NULL;
}
<commit_msg>INTEGRATION: CWS fwkpp3showstop4 (1.12.30); FILE MERGED 2006/05/09 16:39:50 mav 1.12.30.1: #i65066# use internal offset<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Deflater.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: hr $ $Date: 2006-05-11 10:43:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _DEFLATER_HXX_
#include <Deflater.hxx>
#endif
#ifndef _ZLIB_H
#ifdef SYSTEM_ZLIB
#include <zlib.h>
#else
#include <external/zlib/zlib.h>
#endif
#endif
#ifndef _VOS_DIAGNOSE_H_
#include <vos/diagnose.hxx>
#endif
#ifndef _COM_SUN_STAR_PACKAGES_ZIP_ZIPCONSTANTS_HPP_
#include <com/sun/star/packages/zip/ZipConstants.hpp>
#endif
#include <string.h> // for memset

using namespace com::sun::star::packages::zip::ZipConstants;
using namespace com::sun::star;

/** Provides general purpose compression using the ZLIB compression
 * library.
 */

Deflater::~Deflater(void)
{
    end();
}
void Deflater::init (sal_Int32 nLevel, sal_Int32 nStrategy, sal_Bool bNowrap)
{
    pStream = new z_stream;
    /* Memset it to 0...sets zalloc/zfree/opaque to NULL */
    memset (pStream, 0, sizeof(*pStream));

    switch (deflateInit2(pStream, nLevel, Z_DEFLATED, bNowrap? -MAX_WBITS : MAX_WBITS,
                DEF_MEM_LEVEL, nStrategy))
    {
        case Z_OK:
            break;
        case Z_MEM_ERROR:
            delete pStream;
            break;
        case Z_STREAM_ERROR:
            delete pStream;
            break;
        default:
             break;
    }
}
Deflater::Deflater()
: nLevel(DEFAULT_COMPRESSION)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(DEFAULT_COMPRESSION, DEFAULT_STRATEGY, sal_False);
}

Deflater::Deflater(sal_Int32 nSetLevel)
: nLevel(nSetLevel)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(nSetLevel, DEFAULT_STRATEGY, sal_False);
}

Deflater::Deflater(sal_Int32 nSetLevel, sal_Bool bNowrap)
: nLevel(nSetLevel)
, nStrategy(DEFAULT_STRATEGY)
, bFinish(sal_False)
, bFinished(sal_False)
, bSetParams(sal_False)
, nOffset(0)
, nLength(0)
{
    init(nSetLevel, DEFAULT_STRATEGY, bNowrap);
}

sal_Int32 Deflater::doDeflateBytes (uno::Sequence < sal_Int8 > &rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength)
{
    sal_Int32 nResult;
    if (bSetParams)
    {
        pStream->next_in   = (unsigned char*) sInBuffer.getConstArray() + nOffset;
        pStream->next_out  = (unsigned char*) rBuffer.getArray()+nNewOffset;
        pStream->avail_in  = nLength;
        pStream->avail_out = nNewLength;

#ifdef SYSTEM_ZLIB
        nResult = deflateParams(pStream, nLevel, nStrategy);
#else
        nResult = z_deflateParams(pStream, nLevel, nStrategy);
#endif
        switch (nResult)
        {
            case Z_OK:
                bSetParams = sal_False;
                nOffset += nLength - pStream->avail_in;
                nLength = pStream->avail_in;
                return nNewLength - pStream->avail_out;
            case Z_BUF_ERROR:
                bSetParams = sal_False;
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
            default:
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
        }
    }
    else
    {
        pStream->next_in   = (unsigned char*) sInBuffer.getConstArray() + nOffset;
        pStream->next_out  = (unsigned char*) rBuffer.getArray()+nNewOffset;
        pStream->avail_in  = nLength;
        pStream->avail_out = nNewLength;

#ifdef SYSTEM_ZLIB
        nResult = deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH);
#else
        nResult = z_deflate(pStream, bFinish ? Z_FINISH : Z_NO_FLUSH);
#endif
        switch (nResult)
        {
            case Z_STREAM_END:
                bFinished = sal_True;
            case Z_OK:
                nOffset += nLength - pStream->avail_in;
                nLength = pStream->avail_in;
                return nNewLength - pStream->avail_out;
            case Z_BUF_ERROR:
                bSetParams = sal_False;
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
            default:
                VOS_DEBUG_ONLY( pStream->msg );
                return 0;
        }
    }
}

void SAL_CALL Deflater::setInputSegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
        VOS_DEBUG_ONLY("Invalid parameters to Deflater::setInputSegment!");

    sInBuffer = rBuffer;
    nOffset = nNewOffset;
    nLength = nNewLength;
}
void SAL_CALL Deflater::setInput( const uno::Sequence< sal_Int8 >& rBuffer )
{
    sInBuffer = rBuffer;
    nOffset = 0;
    nLength = rBuffer.getLength();
}
void SAL_CALL Deflater::setDictionarySegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (pStream == NULL)
    {
        // do error handling
        VOS_DEBUG_ONLY("No stream!");
    }
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
    {
        // do error handling
    }
#ifdef SYSTEM_ZLIB
    sal_Int32 nResult = deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray()+nOffset, nLength);
#else
    sal_Int32 nResult = z_deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray()+nOffset, nLength);
#endif
}
void SAL_CALL Deflater::setDictionary( const uno::Sequence< sal_Int8 >& rBuffer )
{
    if (pStream == NULL)
    {
        // do error handling
        VOS_DEBUG_ONLY("No stream!");

    }
#ifdef SYSTEM_ZLIB
    sal_Int32 nResult = deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray(), rBuffer.getLength());
#else
    sal_Int32 nResult = z_deflateSetDictionary(pStream, (const unsigned char*)rBuffer.getConstArray(), rBuffer.getLength());
#endif
}
void SAL_CALL Deflater::setStrategy( sal_Int32 nNewStrategy )
{
    if (nNewStrategy != DEFAULT_STRATEGY &&
        nNewStrategy != FILTERED &&
        nNewStrategy != HUFFMAN_ONLY)
    {
        // do error handling
    }
    if (nStrategy != nNewStrategy)
    {
        nStrategy = nNewStrategy;
        bSetParams = sal_True;
    }
}
void SAL_CALL Deflater::setLevel( sal_Int32 nNewLevel )
{
    if ((nNewLevel < 0 || nNewLevel > 9) && nNewLevel != DEFAULT_COMPRESSION)
    {
        // do error handling
    }
    if (nNewLevel != nLevel)
    {
        nLevel = nNewLevel;
        bSetParams = sal_True;
    }
}
sal_Bool SAL_CALL Deflater::needsInput(  )
{
    return nLength <=0;
}
void SAL_CALL Deflater::finish(  )
{
    bFinish = sal_True;
}
sal_Bool SAL_CALL Deflater::finished(  )
{
    return bFinished;
}
sal_Int32 SAL_CALL Deflater::doDeflateSegment( uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
{
    if (nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())
        VOS_DEBUG_ONLY("Invalid Offset or Length passed to doDeflateSegment");
    return doDeflateBytes(rBuffer, nNewOffset, nNewLength);
}
sal_Int32 SAL_CALL Deflater::doDeflate( uno::Sequence< sal_Int8 >& rBuffer )
{
    return doDeflateBytes(rBuffer, 0, rBuffer.getLength());
}

sal_Int32 SAL_CALL Deflater::getAdler(  )
{
    return pStream->adler;
}
sal_Int32 SAL_CALL Deflater::getTotalIn(  )
{
    return pStream->total_in;
}
sal_Int32 SAL_CALL Deflater::getTotalOut(  )
{
    return pStream->total_out;
}
void SAL_CALL Deflater::reset(  )
{
#ifdef SYSTEM_ZLIB
    deflateReset(pStream);
#else
    z_deflateReset(pStream);
#endif
    bFinish = sal_False;
    bFinished = sal_False;
    nOffset = nLength = 0;
}
void SAL_CALL Deflater::end(  )
{
    if (pStream != NULL)
    {
#ifdef SYSTEM_ZLIB
        deflateEnd(pStream);
#else
        z_deflateEnd(pStream);
#endif
        delete pStream;
    }
    pStream = NULL;
}
<|endoftext|>