<commit_before>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: algorithm/ConvexHull.java r407 (JTS-1.12+)
 *
 **********************************************************************/

#include <geos/algorithm/ConvexHull.h>
#include <geos/algorithm/PointLocation.h>
#include <geos/algorithm/Orientation.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/Point.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/LineString.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/util/Interrupt.h>

#include <typeinfo>
#include <algorithm>

#ifndef GEOS_INLINE
# include "geos/algorithm/ConvexHull.inl"
#endif

using namespace geos::geom;

namespace geos {
namespace algorithm { // geos.algorithm

namespace {

/**
 * This is the class used to sort in radial order.
 * It's defined here as it's a static one.
 */
class RadiallyLessThen {

private:

    const Coordinate* origin;

    int
    polarCompare(const Coordinate* o, const Coordinate* p,
                 const Coordinate* q)
    {
        double dxp = p->x - o->x;
        double dyp = p->y - o->y;
        double dxq = q->x - o->x;
        double dyq = q->y - o->y;

        int orient = Orientation::index(*o, *p, *q);

        if(orient == Orientation::COUNTERCLOCKWISE) {
            return 1;
        }
        if(orient == Orientation::CLOCKWISE) {
            return -1;
        }

        // points are collinear - check distance
        double op = dxp * dxp + dyp * dyp;
        double oq = dxq * dxq + dyq * dyq;
        if(op < oq) {
            return -1;
        }
        if(op > oq) {
            return 1;
        }
        return 0;
    }

public:

    RadiallyLessThen(const Coordinate* c): origin(c) {}

    bool
    operator()(const Coordinate* p1, const Coordinate* p2)
    {
        return (polarCompare(origin, p1, p2) == -1);
    }

};

} // unnamed namespace

/* private */
std::unique_ptr<CoordinateSequence>
ConvexHull::toCoordinateSequence(Coordinate::ConstVect& cv)
{
    const CoordinateSequenceFactory* csf =
        geomFactory->getCoordinateSequenceFactory();

    std::vector<Coordinate> vect(cv.size());

    for(size_t i = 0; i < cv.size(); ++i) {
        vect[i] = *(cv[i]); // Coordinate copy
    }

    return csf->create(std::move(vect)); // takes ownership of the vector
}

/* private */
void
ConvexHull::computeOctPts(const Coordinate::ConstVect& p_inputPts,
                          Coordinate::ConstVect& pts)
{
    // Initialize all slots with first input coordinate
    pts = Coordinate::ConstVect(8, p_inputPts[0]);

    for(size_t i = 1, n = p_inputPts.size(); i < n; ++i) {
        if(p_inputPts[i]->x < pts[0]->x) {
            pts[0] = p_inputPts[i];
        }
        if(p_inputPts[i]->x - p_inputPts[i]->y < pts[1]->x - pts[1]->y) {
            pts[1] = p_inputPts[i];
        }
        if(p_inputPts[i]->y > pts[2]->y) {
            pts[2] = p_inputPts[i];
        }
        if(p_inputPts[i]->x + p_inputPts[i]->y > pts[3]->x + pts[3]->y) {
            pts[3] = p_inputPts[i];
        }
        if(p_inputPts[i]->x > pts[4]->x) {
            pts[4] = p_inputPts[i];
        }
        if(p_inputPts[i]->x - p_inputPts[i]->y > pts[5]->x - pts[5]->y) {
            pts[5] = p_inputPts[i];
        }
        if(p_inputPts[i]->y < pts[6]->y) {
            pts[6] = p_inputPts[i];
        }
        if(p_inputPts[i]->x + p_inputPts[i]->y < pts[7]->x + pts[7]->y) {
            pts[7] = p_inputPts[i];
        }
    }

}

/* private */
bool
ConvexHull::computeOctRing(const Coordinate::ConstVect& p_inputPts,
                           Coordinate::ConstVect& dest)
{
    computeOctPts(p_inputPts, dest);

    // Remove consecutive equal Coordinates
    // unique() returns an iterator to the end of the resulting
    // sequence, we erase from there to the end.
    dest.erase(std::unique(dest.begin(), dest.end()), dest.end());

    // points must all lie in a line
    if(dest.size() < 3) {
        return false;
    }

    // close ring
    dest.push_back(dest[0]);

    return true;
}

/* private */
void
ConvexHull::reduce(Coordinate::ConstVect& pts)
{
    Coordinate::ConstVect polyPts;

    if(! computeOctRing(pts, polyPts)) {
        // unable to compute interior polygon for some reason
        return;
    }

    // add points defining polygon
    Coordinate::ConstSet reducedSet;
    reducedSet.insert(polyPts.begin(), polyPts.end());

    /**
     * Add all unique points not in the interior poly.
     * CGAlgorithms.isPointInRing is not defined for points
     * actually on the ring, but this doesn't matter since
     * the points of the interior polygon are forced to be
     * in the reduced set.
     *
     * @@TIP: there should be a std::algo for this
     */
    for(size_t i = 0, n = pts.size(); i < n; ++i) {
        if(!PointLocation::isInRing(*(pts[i]), polyPts)) {
            reducedSet.insert(pts[i]);
        }
    }

    inputPts.assign(reducedSet.begin(), reducedSet.end());

    if(inputPts.size() < 3) {
        padArray3(inputPts);
    }
}

/* private */
void
ConvexHull::padArray3(geom::Coordinate::ConstVect& pts)
{
    for(size_t i = pts.size(); i < 3; ++i) {
        pts.push_back(pts[0]);
    }
}

std::unique_ptr<Geometry>
ConvexHull::getConvexHull()
{
    size_t nInputPts = inputPts.size();

    if(nInputPts == 0) { // Return an empty geometry
        return std::unique_ptr<Geometry>(geomFactory->createEmptyGeometry());
    }

    if(nInputPts == 1) { // Return a Point
        // Copy the Coordinate from the ConstVect
        return std::unique_ptr<Geometry>(geomFactory->createPoint(*(inputPts[0])));
    }

    if(nInputPts == 2) { // Return a LineString
        // Copy all Coordinates from the ConstVect
        auto cs = toCoordinateSequence(inputPts);
        return std::unique_ptr<Geometry>(geomFactory->createLineString(cs.release()));
    }

    // use heuristic to reduce points, if large
    if(nInputPts > 50) {
        reduce(inputPts);
    }

    GEOS_CHECK_FOR_INTERRUPTS();

    // sort points for Graham scan.
    preSort(inputPts);

    GEOS_CHECK_FOR_INTERRUPTS();

    // Use Graham scan to find convex hull.
    Coordinate::ConstVect cHS;
    grahamScan(inputPts, cHS);

    GEOS_CHECK_FOR_INTERRUPTS();

    return lineOrPolygon(cHS);
}

/* private */
void
ConvexHull::preSort(Coordinate::ConstVect& pts)
{
    // find the lowest point in the set. If two or more points have
    // the same minimum y coordinate choose the one with the minimum x.
    // This focal point is put in array location pts[0].
    for(size_t i = 1, n = pts.size(); i < n; ++i) {
        const Coordinate* p0 = pts[0]; // this will change
        const Coordinate* pi = pts[i];
        if((pi->y < p0->y) || ((pi->y == p0->y) && (pi->x < p0->x))) {
            const Coordinate* t = p0;
            pts[0] = pi;
            pts[i] = t;
        }
    }

    // sort the points radially around the focal point.
    std::sort(pts.begin(), pts.end(), RadiallyLessThen(pts[0]));
}

/*private*/
void
ConvexHull::grahamScan(const Coordinate::ConstVect& c,
                       Coordinate::ConstVect& ps)
{
    ps.push_back(c[0]);
    ps.push_back(c[1]);
    ps.push_back(c[2]);

    for(size_t i = 3, n = c.size(); i < n; ++i) {
        const Coordinate* p = ps.back();
        ps.pop_back();
        while(!ps.empty() &&
                Orientation::index(
                    *(ps.back()), *p, *(c[i])) > 0) {
            p = ps.back();
            ps.pop_back();
        }
        ps.push_back(p);
        ps.push_back(c[i]);
    }
    ps.push_back(c[0]);
}

/*private*/
bool
ConvexHull::isBetween(const Coordinate& c1, const Coordinate& c2, const Coordinate& c3)
{
    if(Orientation::index(c1, c2, c3) != 0) {
        return false;
    }
    if(c1.x != c3.x) {
        if(c1.x <= c2.x && c2.x <= c3.x) {
            return true;
        }
        if(c3.x <= c2.x && c2.x <= c1.x) {
            return true;
        }
    }
    if(c1.y != c3.y) {
        if(c1.y <= c2.y && c2.y <= c3.y) {
            return true;
        }
        if(c3.y <= c2.y && c2.y <= c1.y) {
            return true;
        }
    }
    return false;
}

/* private */
std::unique_ptr<Geometry>
ConvexHull::lineOrPolygon(const Coordinate::ConstVect& input)
{
    Coordinate::ConstVect cleaned;

    cleanRing(input, cleaned);

    if(cleaned.size() == 3) { // shouldn't this be 2 ??
        cleaned.resize(2);
        auto cl1 = toCoordinateSequence(cleaned);
        return geomFactory->createLineString(std::move(cl1));
    }
    auto cl2 = toCoordinateSequence(cleaned);
    std::unique_ptr<LinearRing> linearRing = geomFactory->createLinearRing(std::move(cl2));
    return geomFactory->createPolygon(std::move(linearRing));
}

/*private*/
void
ConvexHull::cleanRing(const Coordinate::ConstVect& original,
                      Coordinate::ConstVect& cleaned)
{
    size_t npts = original.size();

    const Coordinate* last = original[npts - 1];

    //util::Assert::equals(*(original[0]), *last);
    assert(last);
    assert(original[0]->equals2D(*last));

    const Coordinate* prev = nullptr;
    for(size_t i = 0; i < npts - 1; ++i) {
        const Coordinate* curr = original[i];
        const Coordinate* next = original[i + 1];

        // skip consecutive equal coordinates
        if(curr->equals2D(*next)) {
            continue;
        }

        if(prev != nullptr &&  isBetween(*prev, *curr, *next)) {
            continue;
        }

        cleaned.push_back(curr);
        prev = curr;
    }

    cleaned.push_back(last);

}

} // namespace geos.algorithm
} // namespace geos

<commit_msg>Minor simplification in ConvexHull<commit_after>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: algorithm/ConvexHull.java r407 (JTS-1.12+)
 *
 **********************************************************************/

#include <geos/algorithm/ConvexHull.h>
#include <geos/algorithm/PointLocation.h>
#include <geos/algorithm/Orientation.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/Point.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/LineString.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/util/Interrupt.h>

#include <typeinfo>
#include <algorithm>

#ifndef GEOS_INLINE
# include "geos/algorithm/ConvexHull.inl"
#endif

using namespace geos::geom;

namespace geos {
namespace algorithm { // geos.algorithm

namespace {

/**
 * This is the class used to sort in radial order.
 * It's defined here as it's a static one.
 */
class RadiallyLessThen {

private:

    const Coordinate* origin;

    int
    polarCompare(const Coordinate* o, const Coordinate* p,
                 const Coordinate* q)
    {
        double dxp = p->x - o->x;
        double dyp = p->y - o->y;
        double dxq = q->x - o->x;
        double dyq = q->y - o->y;

        int orient = Orientation::index(*o, *p, *q);

        if(orient == Orientation::COUNTERCLOCKWISE) {
            return 1;
        }
        if(orient == Orientation::CLOCKWISE) {
            return -1;
        }

        // points are collinear - check distance
        double op = dxp * dxp + dyp * dyp;
        double oq = dxq * dxq + dyq * dyq;
        if(op < oq) {
            return -1;
        }
        if(op > oq) {
            return 1;
        }
        return 0;
    }

public:

    RadiallyLessThen(const Coordinate* c): origin(c) {}

    bool
    operator()(const Coordinate* p1, const Coordinate* p2)
    {
        return (polarCompare(origin, p1, p2) == -1);
    }

};

} // unnamed namespace

/* private */
std::unique_ptr<CoordinateSequence>
ConvexHull::toCoordinateSequence(Coordinate::ConstVect& cv)
{
    const CoordinateSequenceFactory* csf =
        geomFactory->getCoordinateSequenceFactory();

    std::vector<Coordinate> vect(cv.size());

    for(size_t i = 0; i < cv.size(); ++i) {
        vect[i] = *(cv[i]); // Coordinate copy
    }

    return csf->create(std::move(vect)); // takes ownership of the vector
}

/* private */
void
ConvexHull::computeOctPts(const Coordinate::ConstVect& p_inputPts,
                          Coordinate::ConstVect& pts)
{
    // Initialize all slots with first input coordinate
    pts = Coordinate::ConstVect(8, p_inputPts[0]);

    for(size_t i = 1, n = p_inputPts.size(); i < n; ++i) {
        if(p_inputPts[i]->x < pts[0]->x) {
            pts[0] = p_inputPts[i];
        }
        if(p_inputPts[i]->x - p_inputPts[i]->y < pts[1]->x - pts[1]->y) {
            pts[1] = p_inputPts[i];
        }
        if(p_inputPts[i]->y > pts[2]->y) {
            pts[2] = p_inputPts[i];
        }
        if(p_inputPts[i]->x + p_inputPts[i]->y > pts[3]->x + pts[3]->y) {
            pts[3] = p_inputPts[i];
        }
        if(p_inputPts[i]->x > pts[4]->x) {
            pts[4] = p_inputPts[i];
        }
        if(p_inputPts[i]->x - p_inputPts[i]->y > pts[5]->x - pts[5]->y) {
            pts[5] = p_inputPts[i];
        }
        if(p_inputPts[i]->y < pts[6]->y) {
            pts[6] = p_inputPts[i];
        }
        if(p_inputPts[i]->x + p_inputPts[i]->y < pts[7]->x + pts[7]->y) {
            pts[7] = p_inputPts[i];
        }
    }

}

/* private */
bool
ConvexHull::computeOctRing(const Coordinate::ConstVect& p_inputPts,
                           Coordinate::ConstVect& dest)
{
    computeOctPts(p_inputPts, dest);

    // Remove consecutive equal Coordinates
    // unique() returns an iterator to the end of the resulting
    // sequence, we erase from there to the end.
    dest.erase(std::unique(dest.begin(), dest.end()), dest.end());

    // points must all lie in a line
    if(dest.size() < 3) {
        return false;
    }

    // close ring
    dest.push_back(dest[0]);

    return true;
}

/* private */
void
ConvexHull::reduce(Coordinate::ConstVect& pts)
{
    Coordinate::ConstVect polyPts;

    if(! computeOctRing(pts, polyPts)) {
        // unable to compute interior polygon for some reason
        return;
    }

    // add points defining polygon
    Coordinate::ConstSet reducedSet;
    reducedSet.insert(polyPts.begin(), polyPts.end());

    /**
     * Add all unique points not in the interior poly.
     * CGAlgorithms.isPointInRing is not defined for points
     * actually on the ring, but this doesn't matter since
     * the points of the interior polygon are forced to be
     * in the reduced set.
     *
     * @@TIP: there should be a std::algo for this
     */
    for(size_t i = 0, n = pts.size(); i < n; ++i) {
        if(!PointLocation::isInRing(*(pts[i]), polyPts)) {
            reducedSet.insert(pts[i]);
        }
    }

    inputPts.assign(reducedSet.begin(), reducedSet.end());

    if(inputPts.size() < 3) {
        padArray3(inputPts);
    }
}

/* private */
void
ConvexHull::padArray3(geom::Coordinate::ConstVect& pts)
{
    for(size_t i = pts.size(); i < 3; ++i) {
        pts.push_back(pts[0]);
    }
}

std::unique_ptr<Geometry>
ConvexHull::getConvexHull()
{
    size_t nInputPts = inputPts.size();

    if(nInputPts == 0) { // Return an empty geometry
        return geomFactory->createEmptyGeometry();
    }

    if(nInputPts == 1) { // Return a Point
        // Copy the Coordinate from the ConstVect
        return std::unique_ptr<Geometry>(geomFactory->createPoint(*(inputPts[0])));
    }

    if(nInputPts == 2) { // Return a LineString
        // Copy all Coordinates from the ConstVect
        auto cs = toCoordinateSequence(inputPts);
        return geomFactory->createLineString(std::move(cs));
    }

    // use heuristic to reduce points, if large
    if(nInputPts > 50) {
        reduce(inputPts);
    }

    GEOS_CHECK_FOR_INTERRUPTS();

    // sort points for Graham scan.
    preSort(inputPts);

    GEOS_CHECK_FOR_INTERRUPTS();

    // Use Graham scan to find convex hull.
    Coordinate::ConstVect cHS;
    grahamScan(inputPts, cHS);

    GEOS_CHECK_FOR_INTERRUPTS();

    return lineOrPolygon(cHS);
}

/* private */
void
ConvexHull::preSort(Coordinate::ConstVect& pts)
{
    // find the lowest point in the set. If two or more points have
    // the same minimum y coordinate choose the one with the minimum x.
    // This focal point is put in array location pts[0].
    for(size_t i = 1, n = pts.size(); i < n; ++i) {
        const Coordinate* p0 = pts[0]; // this will change
        const Coordinate* pi = pts[i];
        if((pi->y < p0->y) || ((pi->y == p0->y) && (pi->x < p0->x))) {
            const Coordinate* t = p0;
            pts[0] = pi;
            pts[i] = t;
        }
    }

    // sort the points radially around the focal point.
    std::sort(pts.begin(), pts.end(), RadiallyLessThen(pts[0]));
}

/*private*/
void
ConvexHull::grahamScan(const Coordinate::ConstVect& c,
                       Coordinate::ConstVect& ps)
{
    ps.push_back(c[0]);
    ps.push_back(c[1]);
    ps.push_back(c[2]);

    for(size_t i = 3, n = c.size(); i < n; ++i) {
        const Coordinate* p = ps.back();
        ps.pop_back();
        while(!ps.empty() &&
                Orientation::index(
                    *(ps.back()), *p, *(c[i])) > 0) {
            p = ps.back();
            ps.pop_back();
        }
        ps.push_back(p);
        ps.push_back(c[i]);
    }
    ps.push_back(c[0]);
}

/*private*/
bool
ConvexHull::isBetween(const Coordinate& c1, const Coordinate& c2, const Coordinate& c3)
{
    if(Orientation::index(c1, c2, c3) != 0) {
        return false;
    }
    if(c1.x != c3.x) {
        if(c1.x <= c2.x && c2.x <= c3.x) {
            return true;
        }
        if(c3.x <= c2.x && c2.x <= c1.x) {
            return true;
        }
    }
    if(c1.y != c3.y) {
        if(c1.y <= c2.y && c2.y <= c3.y) {
            return true;
        }
        if(c3.y <= c2.y && c2.y <= c1.y) {
            return true;
        }
    }
    return false;
}

/* private */
std::unique_ptr<Geometry>
ConvexHull::lineOrPolygon(const Coordinate::ConstVect& input)
{
    Coordinate::ConstVect cleaned;

    cleanRing(input, cleaned);

    if(cleaned.size() == 3) { // shouldn't this be 2 ??
        cleaned.resize(2);
        auto cl1 = toCoordinateSequence(cleaned);
        return geomFactory->createLineString(std::move(cl1));
    }
    auto cl2 = toCoordinateSequence(cleaned);
    std::unique_ptr<LinearRing> linearRing = geomFactory->createLinearRing(std::move(cl2));
    return geomFactory->createPolygon(std::move(linearRing));
}

/*private*/
void
ConvexHull::cleanRing(const Coordinate::ConstVect& original,
                      Coordinate::ConstVect& cleaned)
{
    size_t npts = original.size();

    const Coordinate* last = original[npts - 1];

    //util::Assert::equals(*(original[0]), *last);
    assert(last);
    assert(original[0]->equals2D(*last));

    const Coordinate* prev = nullptr;
    for(size_t i = 0; i < npts - 1; ++i) {
        const Coordinate* curr = original[i];
        const Coordinate* next = original[i + 1];

        // skip consecutive equal coordinates
        if(curr->equals2D(*next)) {
            continue;
        }

        if(prev != nullptr &&  isBetween(*prev, *curr, *next)) {
            continue;
        }

        cleaned.push_back(curr);
        prev = curr;
    }

    cleaned.push_back(last);

}

} // namespace geos.algorithm
} // namespace geos

<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// ----------------------------------------------------------------------
//
//  SeparableAllocator: Separable Allocator
//
// ----------------------------------------------------------------------

#include "separable.hpp"

#include "booksim.hpp"
#include "roundrobin_arb.hpp"
#include "matrix_arb.hpp"

#include <vector>
#include <iostream>
#include <string.h>
#include <sstream>

SeparableAllocator::SeparableAllocator( Module* parent, const string& name,
					int inputs, int outputs,
					const string& arb_type )
  : Allocator( parent, name, inputs, outputs )
{

  _requests  = new list<sRequest> [inputs] ;

  _input_arb = new Arbiter*[inputs];
  _output_arb = new Arbiter*[outputs];

  ostringstream arb_name;

  for (int i = 0; i < inputs; ++i) {
    arb_name << "arb_i" << i;
    _input_arb[i] = Arbiter::NewArbiter(this, arb_name.str(), arb_type, outputs);
    arb_name.seekp( 0, ios::beg );
  }
  for (int i = 0; i < outputs; ++i) {
    arb_name << "arb_o" << i;
    _output_arb[i] = Arbiter::NewArbiter(this, arb_name.str( ), arb_type, inputs);
    arb_name.seekp( 0, ios::beg );
  }

  Clear() ;
}

SeparableAllocator::~SeparableAllocator() {

  delete[] _requests ;

  for (int i = 0; i < _inputs; ++i) {
    delete _input_arb[i];
  }
  delete[] _input_arb ;

  for (int i = 0; i < _outputs; ++i) {
    delete _output_arb[i];
  }
  delete[] _output_arb ;
}

void SeparableAllocator::Clear() {

  for ( int i = 0 ; i < _inputs ; i++ )
    _requests[i].clear() ;

}

int SeparableAllocator::ReadRequest( int in, int out ) const {
  sRequest r ;
  if ( !ReadRequest( r, in, out) ) {
    return -1 ;
  }
  return r.label ;
}

bool SeparableAllocator::ReadRequest( sRequest &req, int in, int out ) const {

  assert( ( in >= 0 ) && ( in < _inputs ) &&
	  ( out >= 0 ) && ( out < _outputs ) );

  // Only those requests with non-negative priorities should be
  // returned to supress failing speculative allocations. This is
  // a bit of a hack, but is necessary because the router pipeline
  // queuries the results of the allocation through the requests
  int max_pri = -1 ;

  list<sRequest>::const_iterator match = _requests[in].begin() ;

  while ( match != _requests[in].end() ) {
    if ( match->port == out && match->in_pri > max_pri ) {
      req = *match ;
      max_pri = req.in_pri ;
    }
    match++ ;
  }

  return ( max_pri > -1 ) ;

}

void SeparableAllocator::AddRequest( int in, int out, int label, int in_pri,
				     int out_pri ) {

  assert( ( in >= 0 ) && ( in < _inputs ) &&
	  ( out >= 0 ) && ( out < _outputs ) );

  sRequest req ;
  req.port    = out ;
  req.label   = label ;
  req.in_pri  = in_pri ;
  req.out_pri = out_pri ;

  _requests[in].push_front( req ) ;

}

void SeparableAllocator::RemoveRequest( int in, int out, int label ) {
  // Method not implemented yet
  assert( false ) ;

}

void SeparableAllocator::PrintRequests( ostream * os ) const {

  if(!os) os = &cout;

  *os << "Requests = [ ";

  for ( int input = 0 ; input < _inputs ; input++ ) {
    if ( _requests[input].empty() )
      continue ;

    list<sRequest>::const_iterator it  = _requests[input].begin() ;
    list<sRequest>::const_iterator end = _requests[input].end() ;

    *os << input << " -> [ ";
    while ( it != end ) {
      const sRequest& req = *it ;
      *os << "(lbl:" << req.label
	   << ",out:" << req.port
	   << ",ipr:" << req.in_pri
	   << ",opr:" << req.out_pri
	   << ") ";
      it++ ;
    }
    *os << "] ";
  }
  *os << "]." << endl;
}
<commit_msg>Ticket #92: Fix handling of negative priorities in separable allocators.<commit_after>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// ----------------------------------------------------------------------
//
//  SeparableAllocator: Separable Allocator
//
// ----------------------------------------------------------------------

#include "separable.hpp"

#include "booksim.hpp"
#include "roundrobin_arb.hpp"
#include "matrix_arb.hpp"

#include <vector>
#include <iostream>
#include <string.h>
#include <sstream>

SeparableAllocator::SeparableAllocator( Module* parent, const string& name,
					int inputs, int outputs,
					const string& arb_type )
  : Allocator( parent, name, inputs, outputs )
{

  _requests  = new list<sRequest> [inputs] ;

  _input_arb = new Arbiter*[inputs];
  _output_arb = new Arbiter*[outputs];

  ostringstream arb_name;

  for (int i = 0; i < inputs; ++i) {
    arb_name << "arb_i" << i;
    _input_arb[i] = Arbiter::NewArbiter(this, arb_name.str(), arb_type, outputs);
    arb_name.seekp( 0, ios::beg );
  }
  for (int i = 0; i < outputs; ++i) {
    arb_name << "arb_o" << i;
    _output_arb[i] = Arbiter::NewArbiter(this, arb_name.str( ), arb_type, inputs);
    arb_name.seekp( 0, ios::beg );
  }

  Clear() ;
}

SeparableAllocator::~SeparableAllocator() {

  delete[] _requests ;

  for (int i = 0; i < _inputs; ++i) {
    delete _input_arb[i];
  }
  delete[] _input_arb ;

  for (int i = 0; i < _outputs; ++i) {
    delete _output_arb[i];
  }
  delete[] _output_arb ;
}

void SeparableAllocator::Clear() {

  for ( int i = 0 ; i < _inputs ; i++ )
    _requests[i].clear() ;

}

int SeparableAllocator::ReadRequest( int in, int out ) const {
  sRequest r ;
  if ( !ReadRequest( r, in, out) ) {
    return -1 ;
  }
  return r.label ;
}

bool SeparableAllocator::ReadRequest( sRequest &req, int in, int out ) const {

  assert( ( in >= 0 ) && ( in < _inputs ) &&
	  ( out >= 0 ) && ( out < _outputs ) );

  const sRequest * sreq = NULL;

  list<sRequest>::const_iterator match = _requests[in].begin() ;
  while ( match != _requests[in].end() ) {
    if ( ( match->port == out ) && ( !sreq || ( match->in_pri > sreq->in_pri ) ) ) {
      sreq = &(*match) ;
    }
    match++ ;
  }

  if(sreq) {
    req = *sreq;
    return true;
  }
  return false ;

}

void SeparableAllocator::AddRequest( int in, int out, int label, int in_pri,
				     int out_pri ) {

  assert( ( in >= 0 ) && ( in < _inputs ) &&
	  ( out >= 0 ) && ( out < _outputs ) );

  sRequest req ;
  req.port    = out ;
  req.label   = label ;
  req.in_pri  = in_pri ;
  req.out_pri = out_pri ;

  _requests[in].push_front( req ) ;

}

void SeparableAllocator::RemoveRequest( int in, int out, int label ) {
  // Method not implemented yet
  assert( false ) ;

}

void SeparableAllocator::PrintRequests( ostream * os ) const {

  if(!os) os = &cout;

  *os << "Requests = [ ";

  for ( int input = 0 ; input < _inputs ; input++ ) {
    if ( _requests[input].empty() )
      continue ;

    list<sRequest>::const_iterator it  = _requests[input].begin() ;
    list<sRequest>::const_iterator end = _requests[input].end() ;

    *os << input << " -> [ ";
    while ( it != end ) {
      const sRequest& req = *it ;
      *os << "(lbl:" << req.label
	   << ",out:" << req.port
	   << ",ipr:" << req.in_pri
	   << ",opr:" << req.out_pri
	   << ") ";
      it++ ;
    }
    *os << "] ";
  }
  *os << "]." << endl;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SessionPool.h"
#include "ResourceLifecycleManager.h"

using namespace activemq::cmsutil;
using namespace std;

cms::Connection* connection;

ResourceLifecycleManager* resourceLifecycleManager;

decaf::util::concurrent::Mutex mutex;

std::list<PooledSession*> available;

std::list<PooledSession*> sessions;

cms::Session::AcknowledgeMode acknowledgeMode;

////////////////////////////////////////////////////////////////////////////////
SessionPool::SessionPool( cms::Connection* connection,
                          cms::Session::AcknowledgeMode ackMode,
                          ResourceLifecycleManager* resourceLifecycleManager)
    : connection( connection ),
      resourceLifecycleManager( resourceLifecycleManager ),
      mutex(),
      available(),
      sessions(),
      acknowledgeMode( ackMode ) {
}

////////////////////////////////////////////////////////////////////////////////
SessionPool::~SessionPool() {

    // Destroy all of the pooled session objects.
    list<PooledSession*>::iterator iter = sessions.begin();
    for( ; iter != sessions.end(); ++iter ) {
        delete *iter;
    }
    sessions.clear();
    available.clear();
}

////////////////////////////////////////////////////////////////////////////////
PooledSession* SessionPool::takeSession() {

    synchronized(&mutex) {

        PooledSession* pooledSession = NULL;

        // If there are no sessions available, create a new one and return it.
        if( available.size() == 0 ) {

            // No sessions were available - create a new one.
            cms::Session* session = connection->createSession( acknowledgeMode );

            // Give this resource to the life-cycle manager to manage. The pool
            // will not be in charge of destroying this resource.
            resourceLifecycleManager->addSession( session );

            // Now wrap the session with a pooled session.
            pooledSession = new PooledSession( this, session );

            // Add to the sessions list.
            sessions.push_back( pooledSession );

        } else {

            // There are sessions available - use the one at the head of the
            // list, and remove it from the available list.
            pooledSession = available.front();
            available.pop_front();
        }

        // Return the session.
        return pooledSession;
    }

    // Fixes compiler warnings.
    return NULL;
}

////////////////////////////////////////////////////////////////////////////////
void SessionPool::returnSession( PooledSession* session ) {

    synchronized( &mutex ) {

        // Add to the available list.
        available.push_back( session );
    }
}
<commit_msg>cleanup<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SessionPool.h"
#include "ResourceLifecycleManager.h"

using namespace activemq::cmsutil;
using namespace std;

////////////////////////////////////////////////////////////////////////////////
SessionPool::SessionPool( cms::Connection* connection,
                          cms::Session::AcknowledgeMode ackMode,
                          ResourceLifecycleManager* resourceLifecycleManager)
    : connection( connection ),
      resourceLifecycleManager( resourceLifecycleManager ),
      mutex(),
      available(),
      sessions(),
      acknowledgeMode( ackMode ) {
}

////////////////////////////////////////////////////////////////////////////////
SessionPool::~SessionPool() {

    // Destroy all of the pooled session objects.
    list<PooledSession*>::iterator iter = sessions.begin();
    for( ; iter != sessions.end(); ++iter ) {
        delete *iter;
    }
    sessions.clear();
    available.clear();
}

////////////////////////////////////////////////////////////////////////////////
PooledSession* SessionPool::takeSession() {

    synchronized(&mutex) {

        PooledSession* pooledSession = NULL;

        // If there are no sessions available, create a new one and return it.
        if( available.size() == 0 ) {

            // No sessions were available - create a new one.
            cms::Session* session = connection->createSession( acknowledgeMode );

            // Give this resource to the life-cycle manager to manage. The pool
            // will not be in charge of destroying this resource.
            resourceLifecycleManager->addSession( session );

            // Now wrap the session with a pooled session.
            pooledSession = new PooledSession( this, session );

            // Add to the sessions list.
            sessions.push_back( pooledSession );

        } else {

            // There are sessions available - use the one at the head of the
            // list, and remove it from the available list.
            pooledSession = available.front();
            available.pop_front();
        }

        // Return the session.
        return pooledSession;
    }

    // Fixes compiler warnings.
    return NULL;
}

////////////////////////////////////////////////////////////////////////////////
void SessionPool::returnSession( PooledSession* session ) {

    synchronized( &mutex ) {

        // Add to the available list.
        available.push_back( session );
    }
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ActiveMQCPP.h"

#include <decaf/lang/Runtime.h>
#include <activemq/wireformat/WireFormatRegistry.h>
#include <activemq/transport/TransportRegistry.h>

#include <activemq/util/IdGenerator.h>

#include <activemq/wireformat/stomp/StompWireFormatFactory.h>
#include <activemq/wireformat/openwire/OpenWireFormatFactory.h>

#include <activemq/transport/mock/MockTransportFactory.h>
#include <activemq/transport/tcp/TcpTransportFactory.h>
#include <activemq/transport/tcp/SslTransportFactory.h>
#include <activemq/transport/failover/FailoverTransportFactory.h>

using namespace activemq;
using namespace activemq::library;
using namespace activemq::util;
using namespace activemq::transport;
using namespace activemq::transport::tcp;
using namespace activemq::transport::mock;
using namespace activemq::transport::failover;
using namespace activemq::wireformat;

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::initializeLibrary( int argc, char** argv ) {

    // Initialize the Decaf Library by requesting its runtime.
    decaf::lang::Runtime::initializeRuntime( argc, argv );

    // Register all WireFormats
    ActiveMQCPP::registerWireFormats();

    // Register all Transports
    ActiveMQCPP::registerTransports();

    // Start the IdGenerator Kernel
    IdGenerator::initialize();
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::initializeLibrary() {
    ActiveMQCPP::initializeLibrary( 0, NULL );
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::shutdownLibrary() {

    // Shutdown the IdGenerator Kernel
    IdGenerator::shutdown();

    // Now it should be safe to shutdown Decaf.
    decaf::lang::Runtime::shutdownRuntime();
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::registerWireFormats() {

    // Each of the internally implemented WireFormat's is registered here
    // with the WireFormat Registry

    WireFormatRegistry::getInstance().registerFactory(
        "openwire", new wireformat::openwire::OpenWireFormatFactory() );
    WireFormatRegistry::getInstance().registerFactory(
        "stomp", new wireformat::stomp::StompWireFormatFactory() );

}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::registerTransports() {

    // Each of the internally implemented WireFormat's is registered here
    // with the WireFormat Registry

    TransportRegistry::getInstance().registerFactory(
        "tcp", new TcpTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "ssl", new SslTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "mock", new MockTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "failover", new FailoverTransportFactory() );

}
<commit_msg>Do a manual unregister of WireFormat and Transport factories on library shutdown instead of letting the registery destructor handle it, this prevents leak checkers like valgrind from mistakenly reporting memory leaks.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ActiveMQCPP.h"

#include <decaf/lang/Runtime.h>
#include <activemq/wireformat/WireFormatRegistry.h>
#include <activemq/transport/TransportRegistry.h>

#include <activemq/util/IdGenerator.h>

#include <activemq/wireformat/stomp/StompWireFormatFactory.h>
#include <activemq/wireformat/openwire/OpenWireFormatFactory.h>

#include <activemq/transport/mock/MockTransportFactory.h>
#include <activemq/transport/tcp/TcpTransportFactory.h>
#include <activemq/transport/tcp/SslTransportFactory.h>
#include <activemq/transport/failover/FailoverTransportFactory.h>

using namespace activemq;
using namespace activemq::library;
using namespace activemq::util;
using namespace activemq::transport;
using namespace activemq::transport::tcp;
using namespace activemq::transport::mock;
using namespace activemq::transport::failover;
using namespace activemq::wireformat;

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::initializeLibrary( int argc, char** argv ) {

    // Initialize the Decaf Library by requesting its runtime.
    decaf::lang::Runtime::initializeRuntime( argc, argv );

    // Register all WireFormats
    ActiveMQCPP::registerWireFormats();

    // Register all Transports
    ActiveMQCPP::registerTransports();

    // Start the IdGenerator Kernel
    IdGenerator::initialize();
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::initializeLibrary() {
    ActiveMQCPP::initializeLibrary( 0, NULL );
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::shutdownLibrary() {

    // Shutdown the IdGenerator Kernel
    IdGenerator::shutdown();

    // Clear out all registered WireFormat Factories.
    WireFormatRegistry::getInstance().unregisterFactory("openwire");
    WireFormatRegistry::getInstance().unregisterFactory("stomp");

    // Clear out all regsitered Transport factories
    TransportRegistry::getInstance().unregisterFactory("tcp");
    TransportRegistry::getInstance().unregisterFactory("ssl");
    TransportRegistry::getInstance().unregisterFactory("mock");
    TransportRegistry::getInstance().unregisterFactory("failover");

    // Now it should be safe to shutdown Decaf.
    decaf::lang::Runtime::shutdownRuntime();
}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::registerWireFormats() {

    // Each of the internally implemented WireFormat's is registered here
    // with the WireFormat Registry

    WireFormatRegistry::getInstance().registerFactory(
        "openwire", new wireformat::openwire::OpenWireFormatFactory() );
    WireFormatRegistry::getInstance().registerFactory(
        "stomp", new wireformat::stomp::StompWireFormatFactory() );

}

////////////////////////////////////////////////////////////////////////////////
void ActiveMQCPP::registerTransports() {

    // Each of the internally implemented WireFormat's is registered here
    // with the WireFormat Registry

    TransportRegistry::getInstance().registerFactory(
        "tcp", new TcpTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "ssl", new SslTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "mock", new MockTransportFactory() );
    TransportRegistry::getInstance().registerFactory(
        "failover", new FailoverTransportFactory() );

}
<|endoftext|>


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

#ifndef _DXFBLKRD_HXX
#define _DXFBLKRD_HXX

#ifndef _DXFENTRD_HXX
#include <dxfentrd.hxx>
#endif

//----------------------------------------------------------------------------
//---------------- Ein Block (= Menge von Entities) --------------------------
//----------------------------------------------------------------------------

class DXFBlock : public DXFEntities {

public:

    DXFBlock * pSucc;
        // Zeiger auf naechsten Block in der Liste DXFBlocks::pFirst

    // Eigenschaften des Blocks, durch Gruppencodes kommentiert:
    char sName[DXF_MAX_STRING_LEN+1];     //  2
    char sAlsoName[DXF_MAX_STRING_LEN+1]; //  3
    long nFlags;                          // 70
    DXFVector aBasePoint;                 // 10,20,30
    char sXRef[DXF_MAX_STRING_LEN+1];     //  1

    DXFBlock();
    ~DXFBlock();

    void Read(DXFGroupReader & rDGR);
        // Liest den Block (einschliesslich der Entities) per rGDR
        // aus einer DXF-Datei bis zu einem ENDBLK, ENDSEC oder EOF.
};

//----------------------------------------------------------------------------
//---------------- Eine Menge von Bloecken -----------------------------------
//----------------------------------------------------------------------------

class DXFBlocks {

public:

    DXFBlock * pFirst;
        // Liste der Bloecke, READ ONLY!

    DXFBlocks();
    ~DXFBlocks();

    void Read(DXFGroupReader & rDGR);
        // Liesst alle Bloecke per rDGR bis zu einem ENDSEC oder EOF.

    DXFBlock * Search(const char * sName) const;
        // Sucht einen Block mit dem Namen, liefert NULL bei Misserfolg.

    void Clear();
        // Loescht alle Bloecke;

};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.1.1.1.326); FILE MERGED 2005/09/05 15:13:04 rt 1.1.1.1.326.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dxfblkrd.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 02:54:34 $
 *
 *  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 _DXFBLKRD_HXX
#define _DXFBLKRD_HXX

#ifndef _DXFENTRD_HXX
#include <dxfentrd.hxx>
#endif

//----------------------------------------------------------------------------
//---------------- Ein Block (= Menge von Entities) --------------------------
//----------------------------------------------------------------------------

class DXFBlock : public DXFEntities {

public:

    DXFBlock * pSucc;
        // Zeiger auf naechsten Block in der Liste DXFBlocks::pFirst

    // Eigenschaften des Blocks, durch Gruppencodes kommentiert:
    char sName[DXF_MAX_STRING_LEN+1];     //  2
    char sAlsoName[DXF_MAX_STRING_LEN+1]; //  3
    long nFlags;                          // 70
    DXFVector aBasePoint;                 // 10,20,30
    char sXRef[DXF_MAX_STRING_LEN+1];     //  1

    DXFBlock();
    ~DXFBlock();

    void Read(DXFGroupReader & rDGR);
        // Liest den Block (einschliesslich der Entities) per rGDR
        // aus einer DXF-Datei bis zu einem ENDBLK, ENDSEC oder EOF.
};

//----------------------------------------------------------------------------
//---------------- Eine Menge von Bloecken -----------------------------------
//----------------------------------------------------------------------------

class DXFBlocks {

public:

    DXFBlock * pFirst;
        // Liste der Bloecke, READ ONLY!

    DXFBlocks();
    ~DXFBlocks();

    void Read(DXFGroupReader & rDGR);
        // Liesst alle Bloecke per rDGR bis zu einem ENDSEC oder EOF.

    DXFBlock * Search(const char * sName) const;
        // Sucht einen Block mit dem Namen, liefert NULL bei Misserfolg.

    void Clear();
        // Loescht alle Bloecke;

};

#endif

<|endoftext|>


<commit_before>//===- LinkerScript.cpp ---------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the parser/evaluator of the linker script.
// It does not construct an AST but consume linker script directives directly.
// Results are written to Driver or Config object.
//
//===----------------------------------------------------------------------===//

#include "LinkerScript.h"
#include "Config.h"
#include "Driver.h"
#include "InputSection.h"
#include "SymbolTable.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"

using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;

LinkerScript *elf2::Script;

template <class ELFT>
SectionRule *LinkerScript::find(InputSectionBase<ELFT> *S) {
  for (SectionRule &R : Sections)
    if (R.match(S))
      return &R;
  return nullptr;
}

template <class ELFT>
StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
  SectionRule *R = find(S);
  return R ? R->Dest : "";
}

template <class ELFT>
bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {
  return getOutputSection(S) == "/DISCARD/";
}

template <class ELFT> bool LinkerScript::shouldKeep(InputSectionBase<ELFT> *S) {
  SectionRule *R = find(S);
  return R && R->Keep;
}

// A compartor to sort output sections. Returns -1 or 1 if both
// A and B are mentioned in linker scripts. Otherwise, returns 0
// to use the default rule which is implemented in Writer.cpp.
int LinkerScript::compareSections(StringRef A, StringRef B) {
  auto E = SectionOrder.end();
  auto I = std::find(SectionOrder.begin(), E, A);
  auto J = std::find(SectionOrder.begin(), E, B);
  if (I == E || J == E)
    return 0;
  return I < J ? -1 : 1;
}

// Returns true if S matches T. S can contain glob meta-characters.
// The asterisk ('*') matches zero or more characacters, and the question
// mark ('?') matches one character.
static bool matchStr(StringRef S, StringRef T) {
  for (;;) {
    if (S.empty())
      return T.empty();
    if (S[0] == '*') {
      S = S.substr(1);
      if (S.empty())
        // Fast path. If a pattern is '*', it matches anything.
        return true;
      for (size_t I = 0, E = T.size(); I < E; ++I)
        if (matchStr(S, T.substr(I)))
          return true;
      return false;
    }
    if (T.empty() || (S[0] != T[0] && S[0] != '?'))
      return false;
    S = S.substr(1);
    T = T.substr(1);
  }
}

template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {
  return matchStr(SectionPattern, S->getSectionName());
}

class elf2::ScriptParser {
public:
  ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)
      : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {
    Cmd["ENTRY"] = std::mem_fn(&ScriptParser::readEntry);
    Cmd["EXTERN"] = std::mem_fn(&ScriptParser::readExtern);
    Cmd["GROUP"] = std::mem_fn(&ScriptParser::readGroup);
    Cmd["INCLUDE"] = std::mem_fn(&ScriptParser::readInclude);
    Cmd["INPUT"] = std::mem_fn(&ScriptParser::readGroup);
    Cmd["OUTPUT"] = std::mem_fn(&ScriptParser::readOutput);
    Cmd["OUTPUT_ARCH"] = std::mem_fn(&ScriptParser::readOutputArch);
    Cmd["OUTPUT_FORMAT"] = std::mem_fn(&ScriptParser::readOutputFormat);
    Cmd["SEARCH_DIR"] = std::mem_fn(&ScriptParser::readSearchDir);
    Cmd["SECTIONS"] = std::mem_fn(&ScriptParser::readSections);
    Cmd[";"] = [](ScriptParser &) {};
  }

  void run();

private:
  void setError(const Twine &Msg);
  static std::vector<StringRef> tokenize(StringRef S);
  static StringRef skipSpace(StringRef S);
  bool atEOF();
  StringRef next();
  bool skip(StringRef Tok);
  void expect(StringRef Expect);

  void addFile(StringRef Path);

  void readAsNeeded();
  void readEntry();
  void readExtern();
  void readGroup();
  void readInclude();
  void readOutput();
  void readOutputArch();
  void readOutputFormat();
  void readSearchDir();
  void readSections();

  void readOutputSectionDescription();
  void readSectionPatterns(StringRef OutSec, bool Keep);

  StringSaver Saver;
  std::vector<StringRef> Tokens;
  llvm::StringMap<std::function<void(ScriptParser &)>> Cmd;
  size_t Pos = 0;
  bool IsUnderSysroot;
  bool Error = false;
};

void ScriptParser::run() {
  while (!atEOF()) {
    StringRef Tok = next();
    auto It = Cmd.find(Tok);
    if (It != Cmd.end()) {
      std::function<void(ScriptParser &)> &Handler = It->second;
      Handler(*this);
    } else {
      setError("unknown directive: " + Tok);
    }
  }
}

// We don't want to record cascading errors. Keep only the first one.
void ScriptParser::setError(const Twine &Msg) {
  if (Error)
    return;
  error(Msg);
  Error = true;
}

// Split S into linker script tokens.
std::vector<StringRef> ScriptParser::tokenize(StringRef S) {
  std::vector<StringRef> Ret;
  for (;;) {
    S = skipSpace(S);
    if (S.empty())
      return Ret;

    // Quoted token
    if (S.startswith("\"")) {
      size_t E = S.find("\"", 1);
      if (E == StringRef::npos) {
        error("unclosed quote");
        return {};
      }
      Ret.push_back(S.substr(1, E - 1));
      S = S.substr(E + 1);
      continue;
    }

    // Unquoted token
    size_t Pos = S.find_first_not_of(
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        "0123456789_.$/\\~=+[]*?-:");
    // A character that cannot start a word (which is usually a
    // punctuation) forms a single character token.
    if (Pos == 0)
      Pos = 1;
    Ret.push_back(S.substr(0, Pos));
    S = S.substr(Pos);
  }
}

// Skip leading whitespace characters or /**/-style comments.
StringRef ScriptParser::skipSpace(StringRef S) {
  for (;;) {
    if (S.startswith("/*")) {
      size_t E = S.find("*/", 2);
      if (E == StringRef::npos) {
        error("unclosed comment in a linker script");
        return "";
      }
      S = S.substr(E + 2);
      continue;
    }
    size_t Size = S.size();
    S = S.ltrim();
    if (S.size() == Size)
      return S;
  }
}

// An errneous token is handled as if it were the last token before EOF.
bool ScriptParser::atEOF() { return Error || Tokens.size() == Pos; }

StringRef ScriptParser::next() {
  if (Error)
    return "";
  if (atEOF()) {
    setError("unexpected EOF");
    return "";
  }
  return Tokens[Pos++];
}

bool ScriptParser::skip(StringRef Tok) {
  if (Error)
    return false;
  if (atEOF()) {
    setError("unexpected EOF");
    return false;
  }
  if (Tok != Tokens[Pos])
    return false;
  ++Pos;
  return true;
}

void ScriptParser::expect(StringRef Expect) {
  if (Error)
    return;
  StringRef Tok = next();
  if (Tok != Expect)
    setError(Expect + " expected, but got " + Tok);
}

void ScriptParser::addFile(StringRef S) {
  if (IsUnderSysroot && S.startswith("/")) {
    SmallString<128> Path;
    (Config->Sysroot + S).toStringRef(Path);
    if (sys::fs::exists(Path)) {
      Driver->addFile(Saver.save(Path.str()));
      return;
    }
  }

  if (sys::path::is_absolute(S)) {
    Driver->addFile(S);
  } else if (S.startswith("=")) {
    if (Config->Sysroot.empty())
      Driver->addFile(S.substr(1));
    else
      Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
  } else if (S.startswith("-l")) {
    Driver->addLibrary(S.substr(2));
  } else if (sys::fs::exists(S)) {
    Driver->addFile(S);
  } else {
    std::string Path = findFromSearchPaths(S);
    if (Path.empty())
      setError("Unable to find " + S);
    else
      Driver->addFile(Saver.save(Path));
  }
}

void ScriptParser::readAsNeeded() {
  expect("(");
  bool Orig = Config->AsNeeded;
  Config->AsNeeded = true;
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      break;
    addFile(Tok);
  }
  Config->AsNeeded = Orig;
}

void ScriptParser::readEntry() {
  // -e <symbol> takes predecence over ENTRY(<symbol>).
  expect("(");
  StringRef Tok = next();
  if (Config->Entry.empty())
    Config->Entry = Tok;
  expect(")");
}

void ScriptParser::readExtern() {
  expect("(");
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      return;
    Config->Undefined.push_back(Tok);
  }
}

void ScriptParser::readGroup() {
  expect("(");
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      return;
    if (Tok == "AS_NEEDED") {
      readAsNeeded();
      continue;
    }
    addFile(Tok);
  }
}

void ScriptParser::readInclude() {
  StringRef Tok = next();
  auto MBOrErr = MemoryBuffer::getFile(Tok);
  if (!MBOrErr) {
    setError("cannot open " + Tok);
    return;
  }
  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
  StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
  std::vector<StringRef> V = tokenize(S);
  Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
}

void ScriptParser::readOutput() {
  // -o <file> takes predecence over OUTPUT(<file>).
  expect("(");
  StringRef Tok = next();
  if (Config->OutputFile.empty())
    Config->OutputFile = Tok;
  expect(")");
}

void ScriptParser::readOutputArch() {
  // Error checking only for now.
  expect("(");
  next();
  expect(")");
}

void ScriptParser::readOutputFormat() {
  // Error checking only for now.
  expect("(");
  next();
  StringRef Tok = next();
  if (Tok == ")")
   return;
  if (Tok != ",") {
    setError("unexpected token: " + Tok);
    return;
  }
  next();
  expect(",");
  next();
  expect(")");
}

void ScriptParser::readSearchDir() {
  expect("(");
  Config->SearchPaths.push_back(next());
  expect(")");
}

void ScriptParser::readSections() {
  expect("{");
  while (!Error && !skip("}"))
    readOutputSectionDescription();
}

void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) {
  expect("(");
  while (!Error && !skip(")"))
    Script->Sections.emplace_back(OutSec, next(), Keep);
}

void ScriptParser::readOutputSectionDescription() {
  StringRef OutSec = next();
  Script->SectionOrder.push_back(OutSec);
  expect(":");
  expect("{");
  while (!Error && !skip("}")) {
    StringRef Tok = next();
    if (Tok == "*") {
      readSectionPatterns(OutSec, false);
    } else if (Tok == "KEEP") {
      expect("(");
      next(); // Skip *
      readSectionPatterns(OutSec, true);
      expect(")");
    } else {
      setError("Unknown command " + Tok);
    }
  }
}

static bool isUnderSysroot(StringRef Path) {
  if (Config->Sysroot == "")
    return false;
  for (; !Path.empty(); Path = sys::path::parent_path(Path))
    if (sys::fs::equivalent(Config->Sysroot, Path))
      return true;
  return false;
}

// Entry point. The other functions or classes are private to this file.
void LinkerScript::read(MemoryBufferRef MB) {
  StringRef Path = MB.getBufferIdentifier();
  ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();
}

template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);

template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);

template bool LinkerScript::shouldKeep(InputSectionBase<ELF32LE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF32BE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF64LE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF64BE> *);

template bool SectionRule::match(InputSectionBase<ELF32LE> *);
template bool SectionRule::match(InputSectionBase<ELF32BE> *);
template bool SectionRule::match(InputSectionBase<ELF64LE> *);
template bool SectionRule::match(InputSectionBase<ELF64BE> *);
<commit_msg>[ELF] - replaced std::function with raw pointers in LinkerScript.cpp<commit_after>//===- LinkerScript.cpp ---------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the parser/evaluator of the linker script.
// It does not construct an AST but consume linker script directives directly.
// Results are written to Driver or Config object.
//
//===----------------------------------------------------------------------===//

#include "LinkerScript.h"
#include "Config.h"
#include "Driver.h"
#include "InputSection.h"
#include "SymbolTable.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"

using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;

LinkerScript *elf2::Script;

template <class ELFT>
SectionRule *LinkerScript::find(InputSectionBase<ELFT> *S) {
  for (SectionRule &R : Sections)
    if (R.match(S))
      return &R;
  return nullptr;
}

template <class ELFT>
StringRef LinkerScript::getOutputSection(InputSectionBase<ELFT> *S) {
  SectionRule *R = find(S);
  return R ? R->Dest : "";
}

template <class ELFT>
bool LinkerScript::isDiscarded(InputSectionBase<ELFT> *S) {
  return getOutputSection(S) == "/DISCARD/";
}

template <class ELFT> bool LinkerScript::shouldKeep(InputSectionBase<ELFT> *S) {
  SectionRule *R = find(S);
  return R && R->Keep;
}

// A compartor to sort output sections. Returns -1 or 1 if both
// A and B are mentioned in linker scripts. Otherwise, returns 0
// to use the default rule which is implemented in Writer.cpp.
int LinkerScript::compareSections(StringRef A, StringRef B) {
  auto E = SectionOrder.end();
  auto I = std::find(SectionOrder.begin(), E, A);
  auto J = std::find(SectionOrder.begin(), E, B);
  if (I == E || J == E)
    return 0;
  return I < J ? -1 : 1;
}

// Returns true if S matches T. S can contain glob meta-characters.
// The asterisk ('*') matches zero or more characacters, and the question
// mark ('?') matches one character.
static bool matchStr(StringRef S, StringRef T) {
  for (;;) {
    if (S.empty())
      return T.empty();
    if (S[0] == '*') {
      S = S.substr(1);
      if (S.empty())
        // Fast path. If a pattern is '*', it matches anything.
        return true;
      for (size_t I = 0, E = T.size(); I < E; ++I)
        if (matchStr(S, T.substr(I)))
          return true;
      return false;
    }
    if (T.empty() || (S[0] != T[0] && S[0] != '?'))
      return false;
    S = S.substr(1);
    T = T.substr(1);
  }
}

template <class ELFT> bool SectionRule::match(InputSectionBase<ELFT> *S) {
  return matchStr(SectionPattern, S->getSectionName());
}

class elf2::ScriptParser {
  typedef void (ScriptParser::*Handler)();

public:
  ScriptParser(BumpPtrAllocator *A, StringRef S, bool B)
      : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {}

  void run();

private:
  void setError(const Twine &Msg);
  static std::vector<StringRef> tokenize(StringRef S);
  static StringRef skipSpace(StringRef S);
  bool atEOF();
  StringRef next();
  bool skip(StringRef Tok);
  void expect(StringRef Expect);

  void addFile(StringRef Path);

  void readAsNeeded();
  void readEntry();
  void readExtern();
  void readGroup();
  void readInclude();
  void readNothing() {}
  void readOutput();
  void readOutputArch();
  void readOutputFormat();
  void readSearchDir();
  void readSections();

  void readOutputSectionDescription();
  void readSectionPatterns(StringRef OutSec, bool Keep);

  StringSaver Saver;
  std::vector<StringRef> Tokens;
  const static StringMap<Handler> Cmd;
  size_t Pos = 0;
  bool IsUnderSysroot;
  bool Error = false;
};

const StringMap<elf2::ScriptParser::Handler> elf2::ScriptParser::Cmd = {
    {"ENTRY", &ScriptParser::readEntry},
    {"EXTERN", &ScriptParser::readExtern},
    {"GROUP", &ScriptParser::readGroup},
    {"INCLUDE", &ScriptParser::readInclude},
    {"INPUT", &ScriptParser::readGroup},
    {"OUTPUT", &ScriptParser::readOutput},
    {"OUTPUT_ARCH", &ScriptParser::readOutputArch},
    {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat},
    {"SEARCH_DIR", &ScriptParser::readSearchDir},
    {"SECTIONS", &ScriptParser::readSections},
    {";", &ScriptParser::readNothing}};

void ScriptParser::run() {
  while (!atEOF()) {
    StringRef Tok = next();
    if (Handler Fn = Cmd.lookup(Tok))
      (this->*Fn)();
    else
      setError("unknown directive: " + Tok);
  }
}

// We don't want to record cascading errors. Keep only the first one.
void ScriptParser::setError(const Twine &Msg) {
  if (Error)
    return;
  error(Msg);
  Error = true;
}

// Split S into linker script tokens.
std::vector<StringRef> ScriptParser::tokenize(StringRef S) {
  std::vector<StringRef> Ret;
  for (;;) {
    S = skipSpace(S);
    if (S.empty())
      return Ret;

    // Quoted token
    if (S.startswith("\"")) {
      size_t E = S.find("\"", 1);
      if (E == StringRef::npos) {
        error("unclosed quote");
        return {};
      }
      Ret.push_back(S.substr(1, E - 1));
      S = S.substr(E + 1);
      continue;
    }

    // Unquoted token
    size_t Pos = S.find_first_not_of(
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        "0123456789_.$/\\~=+[]*?-:");
    // A character that cannot start a word (which is usually a
    // punctuation) forms a single character token.
    if (Pos == 0)
      Pos = 1;
    Ret.push_back(S.substr(0, Pos));
    S = S.substr(Pos);
  }
}

// Skip leading whitespace characters or /**/-style comments.
StringRef ScriptParser::skipSpace(StringRef S) {
  for (;;) {
    if (S.startswith("/*")) {
      size_t E = S.find("*/", 2);
      if (E == StringRef::npos) {
        error("unclosed comment in a linker script");
        return "";
      }
      S = S.substr(E + 2);
      continue;
    }
    size_t Size = S.size();
    S = S.ltrim();
    if (S.size() == Size)
      return S;
  }
}

// An errneous token is handled as if it were the last token before EOF.
bool ScriptParser::atEOF() { return Error || Tokens.size() == Pos; }

StringRef ScriptParser::next() {
  if (Error)
    return "";
  if (atEOF()) {
    setError("unexpected EOF");
    return "";
  }
  return Tokens[Pos++];
}

bool ScriptParser::skip(StringRef Tok) {
  if (Error)
    return false;
  if (atEOF()) {
    setError("unexpected EOF");
    return false;
  }
  if (Tok != Tokens[Pos])
    return false;
  ++Pos;
  return true;
}

void ScriptParser::expect(StringRef Expect) {
  if (Error)
    return;
  StringRef Tok = next();
  if (Tok != Expect)
    setError(Expect + " expected, but got " + Tok);
}

void ScriptParser::addFile(StringRef S) {
  if (IsUnderSysroot && S.startswith("/")) {
    SmallString<128> Path;
    (Config->Sysroot + S).toStringRef(Path);
    if (sys::fs::exists(Path)) {
      Driver->addFile(Saver.save(Path.str()));
      return;
    }
  }

  if (sys::path::is_absolute(S)) {
    Driver->addFile(S);
  } else if (S.startswith("=")) {
    if (Config->Sysroot.empty())
      Driver->addFile(S.substr(1));
    else
      Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
  } else if (S.startswith("-l")) {
    Driver->addLibrary(S.substr(2));
  } else if (sys::fs::exists(S)) {
    Driver->addFile(S);
  } else {
    std::string Path = findFromSearchPaths(S);
    if (Path.empty())
      setError("Unable to find " + S);
    else
      Driver->addFile(Saver.save(Path));
  }
}

void ScriptParser::readAsNeeded() {
  expect("(");
  bool Orig = Config->AsNeeded;
  Config->AsNeeded = true;
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      break;
    addFile(Tok);
  }
  Config->AsNeeded = Orig;
}

void ScriptParser::readEntry() {
  // -e <symbol> takes predecence over ENTRY(<symbol>).
  expect("(");
  StringRef Tok = next();
  if (Config->Entry.empty())
    Config->Entry = Tok;
  expect(")");
}

void ScriptParser::readExtern() {
  expect("(");
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      return;
    Config->Undefined.push_back(Tok);
  }
}

void ScriptParser::readGroup() {
  expect("(");
  while (!Error) {
    StringRef Tok = next();
    if (Tok == ")")
      return;
    if (Tok == "AS_NEEDED") {
      readAsNeeded();
      continue;
    }
    addFile(Tok);
  }
}

void ScriptParser::readInclude() {
  StringRef Tok = next();
  auto MBOrErr = MemoryBuffer::getFile(Tok);
  if (!MBOrErr) {
    setError("cannot open " + Tok);
    return;
  }
  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
  StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
  std::vector<StringRef> V = tokenize(S);
  Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
}

void ScriptParser::readOutput() {
  // -o <file> takes predecence over OUTPUT(<file>).
  expect("(");
  StringRef Tok = next();
  if (Config->OutputFile.empty())
    Config->OutputFile = Tok;
  expect(")");
}

void ScriptParser::readOutputArch() {
  // Error checking only for now.
  expect("(");
  next();
  expect(")");
}

void ScriptParser::readOutputFormat() {
  // Error checking only for now.
  expect("(");
  next();
  StringRef Tok = next();
  if (Tok == ")")
   return;
  if (Tok != ",") {
    setError("unexpected token: " + Tok);
    return;
  }
  next();
  expect(",");
  next();
  expect(")");
}

void ScriptParser::readSearchDir() {
  expect("(");
  Config->SearchPaths.push_back(next());
  expect(")");
}

void ScriptParser::readSections() {
  expect("{");
  while (!Error && !skip("}"))
    readOutputSectionDescription();
}

void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) {
  expect("(");
  while (!Error && !skip(")"))
    Script->Sections.emplace_back(OutSec, next(), Keep);
}

void ScriptParser::readOutputSectionDescription() {
  StringRef OutSec = next();
  Script->SectionOrder.push_back(OutSec);
  expect(":");
  expect("{");
  while (!Error && !skip("}")) {
    StringRef Tok = next();
    if (Tok == "*") {
      readSectionPatterns(OutSec, false);
    } else if (Tok == "KEEP") {
      expect("(");
      next(); // Skip *
      readSectionPatterns(OutSec, true);
      expect(")");
    } else {
      setError("Unknown command " + Tok);
    }
  }
}

static bool isUnderSysroot(StringRef Path) {
  if (Config->Sysroot == "")
    return false;
  for (; !Path.empty(); Path = sys::path::parent_path(Path))
    if (sys::fs::equivalent(Config->Sysroot, Path))
      return true;
  return false;
}

// Entry point. The other functions or classes are private to this file.
void LinkerScript::read(MemoryBufferRef MB) {
  StringRef Path = MB.getBufferIdentifier();
  ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run();
}

template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32LE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF32BE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64LE> *);
template StringRef LinkerScript::getOutputSection(InputSectionBase<ELF64BE> *);

template bool LinkerScript::isDiscarded(InputSectionBase<ELF32LE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF32BE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64LE> *);
template bool LinkerScript::isDiscarded(InputSectionBase<ELF64BE> *);

template bool LinkerScript::shouldKeep(InputSectionBase<ELF32LE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF32BE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF64LE> *);
template bool LinkerScript::shouldKeep(InputSectionBase<ELF64BE> *);

template bool SectionRule::match(InputSectionBase<ELF32LE> *);
template bool SectionRule::match(InputSectionBase<ELF32BE> *);
template bool SectionRule::match(InputSectionBase<ELF64LE> *);
template bool SectionRule::match(InputSectionBase<ELF64BE> *);
<|endoftext|>


<commit_before>#include "geometry/RipsExpander.hh"
#include "geometry/RipsExpanderTopDown.hh"

#include "tests/Base.hh"

#include "filtrations/Data.hh"

#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include <algorithm>
#include <iterator>
#include <set>
#include <vector>

#include <cmath>

using namespace aleph::geometry;
using namespace aleph::topology;
using namespace aleph;

/** Checks whether co-faces are preceded by their faces in a filtration */
template <class InputIterator> bool isConsistentFiltration( InputIterator begin, InputIterator end )
{
  using Simplex = typename std::iterator_traits<InputIterator>::value_type;

  // Contains all simplices that have already been 'seen' during the
  // traversal. If an unseen face is encountered, we have identified
  // an error.
  std::set<Simplex> seen;

  for( auto it = begin; it != end; ++it )
  {
    seen.insert( *it );

    for( auto itFace = it->begin_boundary(); itFace != it->end_boundary(); ++itFace )
      if( seen.find( *itFace ) == seen.end() )
        return false;
  }

  return true;
}

template <class Data, class Vertex> void triangle()
{
  ALEPH_TEST_BEGIN( "Triangle" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0}, {1}, {2}, {0,1}, {0,2}, {1,2} };

  SimplicialComplex K( simplices.begin(), simplices.end() );
  RipsExpander<SimplicialComplex> ripsExpander;

  auto vr1 = ripsExpander( K, 2 );
  auto vr2 = ripsExpander( K, 3 );

  ALEPH_ASSERT_THROW( vr1.empty() == false );
  ALEPH_ASSERT_THROW( vr2.empty() == false );
  ALEPH_ASSERT_THROW( vr1.size()  == vr2.size() );
  ALEPH_ASSERT_THROW( vr1.size()  == 7 );

  ALEPH_TEST_END();
}

template <class Data, class Vertex> void quad()
{
  ALEPH_TEST_BEGIN( "Quad" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0},
        {1},
        {2},
        {3},
        Simplex( {0,1}, Data(1) ),
        Simplex( {0,2}, Data( std::sqrt(2.0) ) ),
        Simplex( {1,2}, Data(1) ),
        Simplex( {2,3}, Data(1) ),
        Simplex( {0,3}, Data(1) ),
        Simplex( {1,3}, Data( std::sqrt(2.0) ) ) };

  SimplicialComplex K( simplices.begin(), simplices.end() );
  RipsExpander<SimplicialComplex> ripsExpander;

  auto vr1 = ripsExpander( K, 1 );
  auto vr2 = ripsExpander( K, 2 );
  auto vr3 = ripsExpander( K, 3 );

  vr1 = ripsExpander.assignMaximumWeight( vr1 );
  vr2 = ripsExpander.assignMaximumWeight( vr2 );
  vr3 = ripsExpander.assignMaximumWeight( vr3 );

  vr1.sort( filtrations::Data<Simplex>() );
  vr2.sort( filtrations::Data<Simplex>() );
  vr3.sort( filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( vr1.empty() == false );
  ALEPH_ASSERT_THROW( vr2.empty() == false );
  ALEPH_ASSERT_THROW( vr3.empty() == false );

  ALEPH_ASSERT_THROW( vr1.size() == simplices.size()     );
  ALEPH_ASSERT_THROW( vr2.size() == vr1.size()       + 4 ); // +4 triangles
  ALEPH_ASSERT_THROW( vr3.size() == vr2.size()       + 1 ); // +1 tetrahedron

  ALEPH_ASSERT_THROW( isConsistentFiltration( vr1.begin(), vr1.end() ) );
  ALEPH_ASSERT_THROW( isConsistentFiltration( vr2.begin(), vr2.end() ) );
  ALEPH_ASSERT_THROW( isConsistentFiltration( vr3.begin(), vr3.end() ) );

  ALEPH_TEST_END();
}

template <class Data, class Vertex> void expanderComparison()
{
  ALEPH_TEST_BEGIN( "Rips expander comparison" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0},
        {1},
        {2},
        {3},
        Simplex( {0,1}, Data(1) ),
        Simplex( {0,2}, Data( std::sqrt(2.0) ) ),
        Simplex( {1,2}, Data(1) ),
        Simplex( {2,3}, Data(1) ),
        Simplex( {0,3}, Data(1) ),
        Simplex( {1,3}, Data( std::sqrt(2.0) ) ) };

  SimplicialComplex K( simplices.begin(), simplices.end() );

  RipsExpander<SimplicialComplex> re;
  RipsExpanderTopDown<SimplicialComplex> retd;

  auto K1 = re( K, 3 );
  auto K2 = retd( K, 3 );

  ALEPH_ASSERT_EQUAL( K1.size(), K2.size() );

  K1 = re.assignMaximumWeight( K1 );
  K2 = retd.assignMaximumWeight( K2, K );

  K1.sort( aleph::filtrations::Data<Simplex>() );
  K2.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( K1 == K2 );

  auto K3 = retd( K, 3, 2 );
  K3 = retd.assignMaximumWeight( K3, K );

  K3.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( K3.size() < K2.size() );

  {
    auto numSimplices = std::count_if( K2.begin(), K2.end(), [] ( const Simplex& s ) { return s.dimension() >= 2 && s.dimension() <= 3; } );

    ALEPH_ASSERT_EQUAL( decltype(K3.size())( numSimplices ), K3.size() );
  }

  auto K4 = retd( K, 3, 2 );
  K4 = retd.assignMaximumWeight( K4, K4 );
  K4.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_EQUAL( K3.size(), K4.size() );

  {
    auto it1 = K3.begin();
    auto it2 = K4.begin();

    for( ; it1 != K3.end() && it2 != K4.end(); ++it1, ++it2 )
    {
      ALEPH_ASSERT_THROW( *it1 == *it2 );
      ALEPH_ASSERT_EQUAL( it1->data(), it2->data() );
    }
  }

  ALEPH_TEST_END();
}

int main()
{
  triangle<double, unsigned>();
  triangle<double, short   >();
  triangle<float,  unsigned>();
  triangle<float,  short   >();

  quad<double, unsigned>();
  quad<double, short   >();
  quad<float,  unsigned>();
  quad<float,  short   >();

  expanderComparison<double, unsigned>();
  expanderComparison<double, short   >();
  expanderComparison<float,  unsigned>();
  expanderComparison<float,  short   >();
}
<commit_msg>Fixed Rips expander test<commit_after>#include "geometry/RipsExpander.hh"
#include "geometry/RipsExpanderTopDown.hh"

#include "tests/Base.hh"

#include "filtrations/Data.hh"

#include "topology/Simplex.hh"
#include "topology/SimplicialComplex.hh"

#include <algorithm>
#include <iterator>
#include <set>
#include <vector>

#include <cmath>

using namespace aleph::geometry;
using namespace aleph::topology;
using namespace aleph;

/** Checks whether co-faces are preceded by their faces in a filtration */
template <class InputIterator> bool isConsistentFiltration( InputIterator begin, InputIterator end )
{
  using Simplex = typename std::iterator_traits<InputIterator>::value_type;

  // Contains all simplices that have already been 'seen' during the
  // traversal. If an unseen face is encountered, we have identified
  // an error.
  std::set<Simplex> seen;

  for( auto it = begin; it != end; ++it )
  {
    seen.insert( *it );

    for( auto itFace = it->begin_boundary(); itFace != it->end_boundary(); ++itFace )
      if( seen.find( *itFace ) == seen.end() )
        return false;
  }

  return true;
}

template <class Data, class Vertex> void triangle()
{
  ALEPH_TEST_BEGIN( "Triangle" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0}, {1}, {2}, {0,1}, {0,2}, {1,2} };

  SimplicialComplex K( simplices.begin(), simplices.end() );
  RipsExpander<SimplicialComplex> ripsExpander;

  auto vr1 = ripsExpander( K, 2 );
  auto vr2 = ripsExpander( K, 3 );

  ALEPH_ASSERT_THROW( vr1.empty() == false );
  ALEPH_ASSERT_THROW( vr2.empty() == false );
  ALEPH_ASSERT_THROW( vr1.size()  == vr2.size() );
  ALEPH_ASSERT_THROW( vr1.size()  == 7 );

  ALEPH_TEST_END();
}

template <class Data, class Vertex> void quad()
{
  ALEPH_TEST_BEGIN( "Quad" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0},
        {1},
        {2},
        {3},
        Simplex( {0,1}, Data(1) ),
        Simplex( {0,2}, Data( std::sqrt(2.0) ) ),
        Simplex( {1,2}, Data(1) ),
        Simplex( {2,3}, Data(1) ),
        Simplex( {0,3}, Data(1) ),
        Simplex( {1,3}, Data( std::sqrt(2.0) ) ) };

  SimplicialComplex K( simplices.begin(), simplices.end() );
  RipsExpander<SimplicialComplex> ripsExpander;

  auto vr1 = ripsExpander( K, 1 );
  auto vr2 = ripsExpander( K, 2 );
  auto vr3 = ripsExpander( K, 3 );

  vr1 = ripsExpander.assignMaximumWeight( vr1 );
  vr2 = ripsExpander.assignMaximumWeight( vr2 );
  vr3 = ripsExpander.assignMaximumWeight( vr3 );

  vr1.sort( filtrations::Data<Simplex>() );
  vr2.sort( filtrations::Data<Simplex>() );
  vr3.sort( filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( vr1.empty() == false );
  ALEPH_ASSERT_THROW( vr2.empty() == false );
  ALEPH_ASSERT_THROW( vr3.empty() == false );

  ALEPH_ASSERT_THROW( vr1.size() == simplices.size()     );
  ALEPH_ASSERT_THROW( vr2.size() == vr1.size()       + 4 ); // +4 triangles
  ALEPH_ASSERT_THROW( vr3.size() == vr2.size()       + 1 ); // +1 tetrahedron

  ALEPH_ASSERT_THROW( isConsistentFiltration( vr1.begin(), vr1.end() ) );
  ALEPH_ASSERT_THROW( isConsistentFiltration( vr2.begin(), vr2.end() ) );
  ALEPH_ASSERT_THROW( isConsistentFiltration( vr3.begin(), vr3.end() ) );

  ALEPH_TEST_END();
}

template <class Data, class Vertex> void expanderComparison()
{
  ALEPH_TEST_BEGIN( "Rips expander comparison" );

  using Simplex           = Simplex<Data, Vertex>;
  using SimplicialComplex = SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices
    = { {0},
        {1},
        {2},
        {3},
        Simplex( {0,1}, Data(1) ),
        Simplex( {0,2}, Data( std::sqrt(2.0) ) ),
        Simplex( {1,2}, Data(1) ),
        Simplex( {2,3}, Data(1) ),
        Simplex( {0,3}, Data(1) ),
        Simplex( {1,3}, Data( std::sqrt(2.0) ) ) };

  SimplicialComplex K( simplices.begin(), simplices.end() );

  RipsExpander<SimplicialComplex> re;
  RipsExpanderTopDown<SimplicialComplex> retd;

  auto K1 = re( K, 3 );
  auto K2 = retd( K, 3 );

  ALEPH_ASSERT_EQUAL( K1.size(), K2.size() );

  K1 = re.assignMaximumWeight( K1 );
  K2 = retd.assignMaximumWeight( K2, K );

  K1.sort( aleph::filtrations::Data<Simplex>() );
  K2.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( K1 == K2 );

  auto K3 = retd( K, 3, 2 );
  K3 = retd.assignMaximumWeight( K3, K );

  K3.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_THROW( K3.size() < K2.size() );

  {
    auto numSimplices = std::count_if( K2.begin(), K2.end(), [] ( const Simplex& s ) { return s.dimension() >= 2 && s.dimension() <= 3; } );

    ALEPH_ASSERT_EQUAL( decltype(K3.size())( numSimplices ), K3.size() );
  }

  auto K4 = retd( K, 3, 2 );
  K4 = retd.assignMaximumWeight( K4, K );
  K4.sort( aleph::filtrations::Data<Simplex>() );

  ALEPH_ASSERT_EQUAL( K3.size(), K4.size() );

  {
    auto it1 = K3.begin();
    auto it2 = K4.begin();

    for( ; it1 != K3.end() && it2 != K4.end(); ++it1, ++it2 )
    {
      ALEPH_ASSERT_THROW( *it1 == *it2 );
      ALEPH_ASSERT_EQUAL( it1->data(), it2->data() );
    }
  }

  ALEPH_TEST_END();
}

int main()
{
  triangle<double, unsigned>();
  triangle<double, short   >();
  triangle<float,  unsigned>();
  triangle<float,  short   >();

  quad<double, unsigned>();
  quad<double, short   >();
  quad<float,  unsigned>();
  quad<float,  short   >();

  expanderComparison<double, unsigned>();
  expanderComparison<double, short   >();
  expanderComparison<float,  unsigned>();
  expanderComparison<float,  short   >();
}
<|endoftext|>