<commit_before>#include "fluidsystem.h"
#include "camera.h"
#include "vertexrecorder.h"
#include <iostream>
#include <math.h>
#include "particle.h"

using namespace std;

 // your system should at least contain 8x8 particles.
const int N = 5;

const float PARTICLE_SPACING = .2;
const float PARTICLE_RADIUS = PARTICLE_SPACING/2.0;
const int H = PARTICLE_RADIUS;

const float SPRING_CONSTANT = 5; // N/m
const float PARTICLE_MASS = .03; // kg
const float GRAVITY = 9.8; // m/s
const float DRAG_CONSTANT = .05;

FluidSystem::FluidSystem()
{
    // TODO 5. Initialize m_vVecState with cloth particles.
    // You can again use rand_uniform(lo, hi) to make things a bit more interesting
    m_vVecState.clear();
    int particleCount = 0;
    for (unsigned i = 0; i < N; i++){
        for (unsigned j = 0; j< N; j++){
            for (unsigned l = 0; l < N; l++){
                float x = i*PARTICLE_SPACING;
                float y = j*PARTICLE_SPACING;
                float z = l*PARTICLE_SPACING;
                // particles evenly spaced
                Vector3f position = Vector3f(x, y, z);
                // all particles stationary
                Vector3f velocity = Vector3f(0, 0, 0);

                Particle particle = Particle(particleCount, position, velocity);
                m_vVecState.push_back(particle);
                particleCount += 1;
            }
        }
    }
}

std::vector<Particle> FluidSystem::evalF(std::vector<Particle> state)
{

    std::vector<Particle> f;
    // TODO 5. implement evalF
    // - gravity
    // - viscous drag
    // - structural springs
    // - shear springs
    // - flexion springs
    // Particle p = Particle(4.0, Vector3f(0,0,0), Vector3f(0,0,0));

    // Gravity and Wind will be independent of the particle in question

    // F = mg  -> GRAVITY
    // ----------------------------------------
    float gForce = PARTICLE_MASS*GRAVITY;
    // only in the y-direction
    Vector3f gravityForce = Vector3f(0,-gForce, 0);
    // ----------------------------------------
    // 315/[64*pi*h^9]
    float kernel_constant_density = 315.0 / (64.0 * M_PI * pow(H, 9));
    // -45/[pi*h^6]
    float kernel_constant_pressure = -45.0 / (M_PI * pow(H, 6));

    for (unsigned i = 0; i < state.size(); i+=1){
        Particle particle = state[i];
        Vector3f position = particle.getPosition();
        Vector3f velocity = particle.getVelocity();
        float density = particle.getDensity();

        Vector3f viscosity = particle.getViscosity();
        float pressure = particle.getPressure();

        // compute updated density and gradient of pressure
        // based on all other particles
        float density_i = 0;
        Vector3f f_pressure;
        Vector3f f_viscosity;
        for (unsigned j = 0; j < state.size(); j+=1) {
            if (j != i) {
                Particle particle_j = state[j];

                Vector3f delta = position - particle_j.getPosition();

                //  ---------------density computation-----------------
                float kernel_distance_density = pow((H*H - delta.absSquared()), 3);
                density_i += PARTICLE_MASS*kernel_constant_density*kernel_distance_density;

                //  ---------------gradient of pressure computation-----------------

                // Mueller value: (pi + pj) / 2pj
                // Vector3f p_factor = (pressure+particle_j.getPressure()) / (2*particle_j.getDensity());
                float p_factor = pressure/density + particle_j.getPressure()/particle_j.getDensity();
                // (h-d)^2 * d/|d|
                Vector3f kernel_distance_pressure = pow((H - delta.absSquared()), 2) * delta / delta.abs();

                f_pressure += PARTICLE_MASS*p_factor*kernel_constant_pressure*kernel_distance_pressure;
                //  ---------------viscosity computation-----------------
                float kernel_distance_viscosity = H-delta.abs();
                Vector3f v_factor = (particle_j.getViscosity() - viscosity) / particle_j.getDensity();

                f_viscosity += PARTICLE_MASS*v_factor*-1.0*kernel_constant_pressure*kernel_distance_viscosity;

                // printf("F Pressure: ");
                // f_pressure.print();
                // printf("F Viscosity: ");
                // f_viscosity.print();
            }
        }

        // Total Force
        Vector3f totalForce = gravityForce - f_pressure + f_viscosity;

        Vector3f acceleration = (1.0/PARTICLE_MASS)*totalForce;

        if (position.y() < -0.95){
            velocity = Vector3f(velocity.x(), 0, velocity.z());
        }

        Particle newParticle = Particle(i, velocity, acceleration);
        newParticle.setDensity(density_i);
        f.push_back(newParticle);
    }

    return f;
}

void FluidSystem::draw(GLProgram& gl)
{
    //TODO 5: render the system
    //         - ie draw the particles as little spheres
    //         - or draw the springs as little lines or cylinders
    //         - or draw wireframe mesh

    const Vector3f blue(0.0f, 0.0f, 1.0f);

    // EXAMPLE for how to render cloth particles.
    //  - you should replace this code.
    // EXAMPLE: This shows you how to render lines to debug the spring system.
    //
    //          You should replace this code.
    //
    //          Since lines don't have a clearly defined normal, we can't use
    //          a regular lighting model.
    //          GLprogram has a "color only" mode, where illumination
    //          is disabled, and you specify color directly as vertex attribute.
    //          Note: enableLighting/disableLighting invalidates uniforms,
    //          so you'll have to update the transformation/material parameters
    //          after a mode change.
    gl.disableLighting();
    gl.updateModelMatrix(Matrix4f::identity()); // update uniforms after mode change
    // drawBox(Vector3f(0,0,0), 1);

    // not working :(
    gl.updateMaterial(blue);

    for (unsigned i = 0; i < m_vVecState.size(); i+=1){
        Particle p = m_vVecState[i];
        Vector3f pos = p.getPosition();
        gl.updateModelMatrix(Matrix4f::translation(pos));
        drawSphere(PARTICLE_RADIUS, 5, 4);
    }

    gl.enableLighting(); // reset to default lighting model
}

<commit_msg>implemented clamping for kernel functions<commit_after>#include "fluidsystem.h"
#include "camera.h"
#include "vertexrecorder.h"
#include <iostream>
#include <math.h>
#include "particle.h"

using namespace std;

 // your system should at least contain 8x8 particles.
const int N = 5;

const float PARTICLE_SPACING = .2;
const float PARTICLE_RADIUS = PARTICLE_SPACING/2.0;
const int H = PARTICLE_RADIUS;

const float SPRING_CONSTANT = 5; // N/m
const float PARTICLE_MASS = .03; // kg
const float GRAVITY = 9.8; // m/s
const float DRAG_CONSTANT = .05;

FluidSystem::FluidSystem()
{
    // TODO 5. Initialize m_vVecState with cloth particles.
    // You can again use rand_uniform(lo, hi) to make things a bit more interesting
    m_vVecState.clear();
    int particleCount = 0;
    for (unsigned i = 0; i < N; i++){
        for (unsigned j = 0; j< N; j++){
            for (unsigned l = 0; l < N; l++){
                float x = i*PARTICLE_SPACING;
                float y = j*PARTICLE_SPACING;
                float z = l*PARTICLE_SPACING;
                // particles evenly spaced
                Vector3f position = Vector3f(x, y, z);
                // all particles stationary
                Vector3f velocity = Vector3f(0, 0, 0);

                Particle particle = Particle(particleCount, position, velocity);
                m_vVecState.push_back(particle);
                particleCount += 1;
            }
        }
    }
}

std::vector<Particle> FluidSystem::evalF(std::vector<Particle> state)
{

    std::vector<Particle> f;
    // TODO 5. implement evalF
    // - gravity
    // - viscous drag
    // - structural springs
    // - shear springs
    // - flexion springs
    // Particle p = Particle(4.0, Vector3f(0,0,0), Vector3f(0,0,0));

    // Gravity and Wind will be independent of the particle in question

    // F = mg  -> GRAVITY
    // ----------------------------------------
    float gForce = PARTICLE_MASS*GRAVITY;
    // only in the y-direction
    Vector3f gravityForce = Vector3f(0,-gForce, 0);
    // ----------------------------------------
    // 315/[64*pi*h^9]
    float kernel_constant_density = 315.0 / (64.0 * M_PI * pow(H, 9));
    // -45/[pi*h^6]
    float kernel_constant_pressure = -45.0 / (M_PI * pow(H, 6));

    for (unsigned i = 0; i < state.size(); i+=1){
        Particle particle = state[i];
        Vector3f position = particle.getPosition();
        Vector3f velocity = particle.getVelocity();
        float density = particle.getDensity();

        Vector3f viscosity = particle.getViscosity();
        float pressure = particle.getPressure();

        // compute updated density and gradient of pressure
        // based on all other particles
        float density_i = 0;
        Vector3f f_pressure;
        Vector3f f_viscosity;
        for (unsigned j = 0; j < state.size(); j+=1) {
            if (j != i) {
                Particle particle_j = state[j];

                Vector3f delta = position - particle_j.getPosition();

                //  ---------------density computation-----------------
                float kernel_distance_density = pow((H*H - delta.absSquared()), 3);
                if (delta.abs() < H) {
                    kernel_distance_density = 0;
                }
                cout << kernel_distance_density << endl;
                density_i += PARTICLE_MASS*kernel_constant_density*kernel_distance_density;

                //  ---------------gradient of pressure computation-----------------

                // Mueller value: (pi + pj) / 2pj
                // Vector3f p_factor = (pressure+particle_j.getPressure()) / (2*particle_j.getDensity());
                float p_factor = pressure/density + particle_j.getPressure()/particle_j.getDensity();
                // (h-d)^2 * d/|d|
                Vector3f kernel_distance_pressure = pow((H - delta.absSquared()), 2) * delta / delta.abs();

                f_pressure += PARTICLE_MASS*p_factor*kernel_constant_pressure*kernel_distance_pressure;
                //  ---------------viscosity computation-----------------
                float kernel_distance_viscosity = H-delta.abs();
                if (delta.abs() < H) {
                    kernel_distance_viscosity = 0;
                }
                Vector3f v_factor = (particle_j.getViscosity() - viscosity) / particle_j.getDensity();

                f_viscosity += PARTICLE_MASS*v_factor*-1.0*kernel_constant_pressure*kernel_distance_viscosity;

                // printf("F Pressure: ");
                // f_pressure.print();
                // printf("F Viscosity: ");
                // f_viscosity.print();
            }
        }

        // Total Force
        Vector3f totalForce = gravityForce - f_pressure + f_viscosity;

        Vector3f acceleration = (1.0/PARTICLE_MASS)*totalForce;

        if (position.y() < -0.95){
            velocity = Vector3f(velocity.x(), 0, velocity.z());
        }

        Particle newParticle = Particle(i, velocity, acceleration);
        newParticle.setDensity(density_i);
        f.push_back(newParticle);
    }

    return f;
}

void FluidSystem::draw(GLProgram& gl)
{
    //TODO 5: render the system
    //         - ie draw the particles as little spheres
    //         - or draw the springs as little lines or cylinders
    //         - or draw wireframe mesh

    const Vector3f blue(0.0f, 0.0f, 1.0f);

    // EXAMPLE for how to render cloth particles.
    //  - you should replace this code.
    // EXAMPLE: This shows you how to render lines to debug the spring system.
    //
    //          You should replace this code.
    //
    //          Since lines don't have a clearly defined normal, we can't use
    //          a regular lighting model.
    //          GLprogram has a "color only" mode, where illumination
    //          is disabled, and you specify color directly as vertex attribute.
    //          Note: enableLighting/disableLighting invalidates uniforms,
    //          so you'll have to update the transformation/material parameters
    //          after a mode change.
    gl.disableLighting();
    gl.updateModelMatrix(Matrix4f::identity()); // update uniforms after mode change
    // drawBox(Vector3f(0,0,0), 1);

    // not working :(
    gl.updateMaterial(blue);

    for (unsigned i = 0; i < m_vVecState.size(); i+=1){
        Particle p = m_vVecState[i];
        Vector3f pos = p.getPosition();
        gl.updateModelMatrix(Matrix4f::translation(pos));
        drawSphere(PARTICLE_RADIUS, 5, 4);
    }

    gl.enableLighting(); // reset to default lighting model
}

<|endoftext|>


<commit_before>//
//  globe.cpp
//  GlobeVisualization
//
//  Created by Johannes Neumeier on 03/06/15.
//
//

#include "globe.h"

globe::globe() {
    sphere.setRadius(100);
}

void globe::update() {

}

void globe::draw() {

    ofPushMatrix();

    ofSetColor(255);

    sphere.enableNormals();
    sphere.enableTextures();

    ofTexture tex = textureImage.getTextureReference();

    //tex.bind();
    sphere.mapTexCoordsFromTexture(tex);
    //tex.draw(0, 0);
    tex.bind();

    ofRotateX(180);

    sphere.draw();
    textureImage.unbind();

    ofSetColor(150, 255, 100);
    sphere.drawNormals(5);
    sphere.drawAxes(150);

    ofSetLineWidth(0.5);
    ofSetColor(0, 50, 75, 50);
    sphere.drawWireframe();

    ofPopMatrix();

}

void globe::setTexture(string path) {
    textureImage.loadImage(path);
    textureImage.mirror(false, true); // vertical, horizontal
}<commit_msg>finally figured out a fix to the transparency rendering issue... open gl backface culling to the rescue<commit_after>//
//  globe.cpp
//  GlobeVisualization
//
//  Created by Johannes Neumeier on 03/06/15.
//
//

#include "globe.h"

globe::globe() {
    sphere.setRadius(100);
}

void globe::update() {

}

void globe::draw() {

    ofPushMatrix();

    ofSetColor(255);

    //sphere.enableNormals();
    sphere.enableTextures();

    textureImage.getTextureReference().bind();

    ofRotateX(180);

    // enable solid surface and backface culling in Open GL
    glEnable(GL_CULL_FACE); // Cull back facing polygons
    glCullFace(GL_FRONT);

    sphere.draw();
    textureImage.unbind();

    ofSetColor(150, 255, 100);
    //sphere.drawNormals(5);
    sphere.drawAxes(150);

    ofSetLineWidth(0.5);
    ofSetColor(0, 50, 75, 50);
    sphere.drawWireframe();

    ofPopMatrix();

}

void globe::setTexture(string path) {
    textureImage.loadImage(path);
    textureImage.mirror(false, true); // vertical, horizontal
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 */

#include "PeruseConfig.h"

#include <KFileMetaData/UserMetaData>
#include <KConfig>
#include <KConfigGroup>
#include <KNSCore/Engine>

#include <QTimer>
#include <QFile>

class PeruseConfig::Private
{
public:
    Private()
        : config("peruserc")
    {};
    KConfig config;
};

PeruseConfig::PeruseConfig(QObject* parent)
    : QObject(parent)
    , d(new Private)
{
    QStringList locations = d->config.group("general").readEntry("book locations", QStringList());
    if(locations.count() < 1)
    {
        locations = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
        locations << QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
        locations << QString("%1/comics").arg(QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).first());
        d->config.group("general").writeEntry("book locations", locations);
        d->config.sync();
    }
}

PeruseConfig::~PeruseConfig()
{
    delete d;
}

void PeruseConfig::bookOpened(QString path)
{
    QStringList recent = recentlyOpened();

    int i = recent.indexOf(path);
    if(i == 0)
    {
        // This is already first, don't do work we don't need to, because that's just silly
        return;
    }
    else
    {
        recent.removeAll(path);
        recent.prepend(path);
    }
    d->config.group("general").writeEntry("recently opened", recent);
    d->config.sync();
    emit recentlyOpenedChanged();
}

QStringList PeruseConfig::recentlyOpened() const
{
    QStringList recent = d->config.group("general").readEntry("recently opened", QStringList());
    QStringList actualRecent;
    while(recent.count() > 0) {
        QString current = recent.takeFirst();
        if(QFile::exists(current)) {
            actualRecent.append(current);
        }
    }
    return actualRecent;
}

void PeruseConfig::addBookLocation(const QString& location)
{
    if(location.startsWith("file://"))
    {
#ifdef Q_OS_WIN
        QString newLocation = location.mid(8);
#else
        QString newLocation = location.mid(7);
#endif
        QStringList locations = bookLocations();
        // First, get rid of all the entries which start with the newly added location, because that's silly
        QStringList newLocations;
        bool alreadyInThere = false;
        Q_FOREACH(QString entry, locations) {
            if(!entry.startsWith(newLocation))
            {
                newLocations.append(entry);
            }
            if(newLocation.startsWith(entry))
            {
                alreadyInThere = true;
            }
        }
        if(alreadyInThere)
        {
            // Don't be silly, don't add a new location if it's already covered by something more high level...
            emit showMessage("Attempted to add a new location to the list of search folders which is a sub-folder to something already in the list.");
            return;
        }
        newLocations.append(newLocation);
        d->config.group("general").writeEntry("book locations", newLocations);
        d->config.sync();
        emit bookLocationsChanged();
    }
}

void PeruseConfig::removeBookLocation(const QString& location)
{
    QStringList locations = bookLocations();
    locations.removeAll(location);
    d->config.group("general").writeEntry("book locations", locations);
    d->config.sync();
    QTimer::singleShot(100, this, SIGNAL(bookLocationsChanged()));
}

QStringList PeruseConfig::bookLocations() const
{
    QStringList locations = d->config.group("general").readEntry("book locations", QStringList());
    return locations;
}

QString PeruseConfig::newstuffLocation() const
{
    const QStringList locations = KNSCore::Engine::configSearchLocations();
    QString knsrc;
    for (const QString& location : locations) {
        knsrc = QString::fromLocal8Bit("%1/peruse.knsrc").arg(location);
        if (QFile(knsrc).exists()) {
            break;
        }
    }
    if(qEnvironmentVariableIsSet("APPDIR"))
    {
        // Because appimage install happens into /app/usr...
        knsrc = knsrc.prepend("/usr").prepend(qgetenv("APPDIR"));
    }
    return knsrc;
}

QString PeruseConfig::homeDir() const
{
    return QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first();
}

void PeruseConfig::setFilesystemProperty(QString fileName, QString propertyName, QString value)
{
    KFileMetaData::UserMetaData data(fileName);
    if (propertyName == "rating") {
        data.setRating(value.toInt());
    } else if (propertyName == "tags") {
        data.setTags(value.split(","));
    } else if (propertyName == "comment") {
        data.setUserComment(value);
    } else {
        data.setAttribute(QString("peruse.").append(propertyName), value);
    }
}

QString PeruseConfig::getFilesystemProperty(QString fileName, QString propertyName)
{
    QString value;
    KFileMetaData::UserMetaData data(fileName);
    if (propertyName == "rating") {
        value = QString::number(data.rating());
    } else if (propertyName == "tags") {
        value = data.tags().join(",");
    } else if (propertyName == "comment") {
        value = data.userComment();
    } else {
        value = data.attribute(QString("peruse.").append(propertyName));
    }
    return value;
}
<commit_msg>Add mimetype and bytes getters for the file info fetcher<commit_after>/*
 * Copyright (C) 2016 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 */

#include "PeruseConfig.h"

#include <KFileMetaData/UserMetaData>
#include <KConfig>
#include <KConfigGroup>
#include <KNSCore/Engine>

#include <QTimer>
#include <QFile>
#include <QFileInfo>
#include <QMimeDatabase>

class PeruseConfig::Private
{
public:
    Private()
        : config("peruserc")
    {};
    KConfig config;
};

PeruseConfig::PeruseConfig(QObject* parent)
    : QObject(parent)
    , d(new Private)
{
    QStringList locations = d->config.group("general").readEntry("book locations", QStringList());
    if(locations.count() < 1)
    {
        locations = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
        locations << QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
        locations << QString("%1/comics").arg(QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).first());
        d->config.group("general").writeEntry("book locations", locations);
        d->config.sync();
    }
}

PeruseConfig::~PeruseConfig()
{
    delete d;
}

void PeruseConfig::bookOpened(QString path)
{
    QStringList recent = recentlyOpened();

    int i = recent.indexOf(path);
    if(i == 0)
    {
        // This is already first, don't do work we don't need to, because that's just silly
        return;
    }
    else
    {
        recent.removeAll(path);
        recent.prepend(path);
    }
    d->config.group("general").writeEntry("recently opened", recent);
    d->config.sync();
    emit recentlyOpenedChanged();
}

QStringList PeruseConfig::recentlyOpened() const
{
    QStringList recent = d->config.group("general").readEntry("recently opened", QStringList());
    QStringList actualRecent;
    while(recent.count() > 0) {
        QString current = recent.takeFirst();
        if(QFile::exists(current)) {
            actualRecent.append(current);
        }
    }
    return actualRecent;
}

void PeruseConfig::addBookLocation(const QString& location)
{
    if(location.startsWith("file://"))
    {
#ifdef Q_OS_WIN
        QString newLocation = location.mid(8);
#else
        QString newLocation = location.mid(7);
#endif
        QStringList locations = bookLocations();
        // First, get rid of all the entries which start with the newly added location, because that's silly
        QStringList newLocations;
        bool alreadyInThere = false;
        Q_FOREACH(QString entry, locations) {
            if(!entry.startsWith(newLocation))
            {
                newLocations.append(entry);
            }
            if(newLocation.startsWith(entry))
            {
                alreadyInThere = true;
            }
        }
        if(alreadyInThere)
        {
            // Don't be silly, don't add a new location if it's already covered by something more high level...
            emit showMessage("Attempted to add a new location to the list of search folders which is a sub-folder to something already in the list.");
            return;
        }
        newLocations.append(newLocation);
        d->config.group("general").writeEntry("book locations", newLocations);
        d->config.sync();
        emit bookLocationsChanged();
    }
}

void PeruseConfig::removeBookLocation(const QString& location)
{
    QStringList locations = bookLocations();
    locations.removeAll(location);
    d->config.group("general").writeEntry("book locations", locations);
    d->config.sync();
    QTimer::singleShot(100, this, SIGNAL(bookLocationsChanged()));
}

QStringList PeruseConfig::bookLocations() const
{
    QStringList locations = d->config.group("general").readEntry("book locations", QStringList());
    return locations;
}

QString PeruseConfig::newstuffLocation() const
{
    const QStringList locations = KNSCore::Engine::configSearchLocations();
    QString knsrc;
    for (const QString& location : locations) {
        knsrc = QString::fromLocal8Bit("%1/peruse.knsrc").arg(location);
        if (QFile(knsrc).exists()) {
            break;
        }
    }
    if(qEnvironmentVariableIsSet("APPDIR"))
    {
        // Because appimage install happens into /app/usr...
        knsrc = knsrc.prepend("/usr").prepend(qgetenv("APPDIR"));
    }
    return knsrc;
}

QString PeruseConfig::homeDir() const
{
    return QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first();
}

void PeruseConfig::setFilesystemProperty(QString fileName, QString propertyName, QString value)
{
    KFileMetaData::UserMetaData data(fileName);
    if (propertyName == "rating") {
        data.setRating(value.toInt());
    } else if (propertyName == "tags") {
        data.setTags(value.split(","));
    } else if (propertyName == "comment") {
        data.setUserComment(value);
    } else {
        data.setAttribute(QString("peruse.").append(propertyName), value);
    }
}

QString PeruseConfig::getFilesystemProperty(QString fileName, QString propertyName)
{
    QString value;
    KFileMetaData::UserMetaData data(fileName);
    if (propertyName == "rating") {
        value = QString::number(data.rating());
    } else if (propertyName == "tags") {
        value = data.tags().join(",");
    } else if (propertyName == "comment") {
        value = data.userComment();
    } else if (propertyName == "bytes") {
        value = QString::number(QFileInfo(fileName).size());
    } else if (propertyName == "mimetype") {
        QMimeDatabase db;
        QMimeType mime = db.mimeTypeForFile(fileName);
        value = mime.name();
    } else {
        value = data.attribute(QString("peruse.").append(propertyName));
    }
    return value;
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2013      Adrian Draghici <draghici.adrian.b@gmail.com>
//

// Self
#include "EditGroundOverlayDialog.h"
#include "ui_EditGroundOverlayDialog.h"

// Qt
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>

namespace Marble
{

class EditGroundOverlayDialog::Private : public Ui::UiEditGroundOverlayDialog
{

public:
    GeoDataGroundOverlay *m_overlay;
    TextureLayer         *m_textureLayer;

    Private( GeoDataGroundOverlay *overlay, TextureLayer *textureLayer );
    ~Private();

    void updateCoordinates();
};

EditGroundOverlayDialog::Private::Private( GeoDataGroundOverlay *overlay, TextureLayer *textureLayer ) :
    Ui::UiEditGroundOverlayDialog(),
    m_overlay( overlay ),
    m_textureLayer( textureLayer )
{
    // nothing to do
}

EditGroundOverlayDialog::Private::~Private()
{
    // nothing to do
}

EditGroundOverlayDialog::EditGroundOverlayDialog( GeoDataGroundOverlay *overlay,
                                                  TextureLayer *textureLayer,
                                                  QWidget *parent ) :
    QDialog( parent ),
    d( new Private( overlay, textureLayer ) )
{
    d->setupUi( this );

    d->m_header->setName( overlay->name() );
    d->m_header->setIconLink( overlay->absoluteIconFile() );
    d->m_header->setPositionVisible(false);
    d->m_description->setText( overlay->description() );

    d->m_north->setRange( -90, 90 );
    d->m_south->setRange( -90, 90 );
    d->m_west->setRange( -180, 180 );
    d->m_east->setRange( -180, 180 );
    d->m_rotation->setRange( -360, 360 );

    GeoDataLatLonBox latLonBox = overlay->latLonBox();
    d->m_north->setValue( latLonBox.north( GeoDataCoordinates::Degree ) );
    d->m_south->setValue( latLonBox.south( GeoDataCoordinates::Degree ) );
    d->m_west->setValue( latLonBox.west( GeoDataCoordinates::Degree ) );
    d->m_east->setValue( latLonBox.east( GeoDataCoordinates::Degree ) );
    d->m_rotation->setValue( latLonBox.rotation( GeoDataCoordinates::Degree ) );

    connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) );
    connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(clicked()), this, SLOT(updateGroundOverlay()) );
    connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(clicked()), this, SLOT(setGroundOverlayUpdated()) );
    connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(clicked()), d->m_textureLayer, SLOT(reset()) );
}

EditGroundOverlayDialog::~EditGroundOverlayDialog()
{
    delete d;
}

void EditGroundOverlayDialog::updateGroundOverlay()
{
    d->m_overlay->setName( d->m_header->name() );
    d->m_overlay->setIconFile( d->m_header->iconLink() );
    d->m_overlay->setDescription( d->m_description->toPlainText() );

    d->m_overlay->latLonBox().setBoundaries( d->m_north->value(),
                                             d->m_south->value(),
                                             d->m_east->value(),
                                             d->m_west->value(),
                                             GeoDataCoordinates::Degree  );

    d->m_overlay->latLonBox().setRotation( d->m_rotation->value(), GeoDataCoordinates::Degree );
}

void EditGroundOverlayDialog::setGroundOverlayUpdated()
{
    emit groundOverlayUpdated( d->m_overlay );
}

void EditGroundOverlayDialog::checkFields()
{
    if ( d->m_header->name().isEmpty() ) {
        QMessageBox::warning( this,
                              tr( "No name specified" ),
                              tr( "Please specify a name for this ground overlay." ) );
    } else if ( d->m_header->iconLink().isEmpty() ) {
        QMessageBox::warning( this,
                              tr( "No image specified" ),
                              tr( "Please specify an image file." ) );
    } else if( !QFileInfo( d->m_header->iconLink() ).exists() ) {
        QMessageBox::warning( this,
                              tr( "Invalid image path" ),
                              tr( "Please specify a valid path for the image file." ) );
    } else {
        accept();
    }
}

}

#include "EditGroundOverlayDialog.moc"
<commit_msg>REVIEW: 122977<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2013      Adrian Draghici <draghici.adrian.b@gmail.com>
//

// Self
#include "EditGroundOverlayDialog.h"
#include "ui_EditGroundOverlayDialog.h"

// Qt
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>

namespace Marble
{

class EditGroundOverlayDialog::Private : public Ui::UiEditGroundOverlayDialog
{

public:
    GeoDataGroundOverlay *m_overlay;
    TextureLayer         *m_textureLayer;

    Private( GeoDataGroundOverlay *overlay, TextureLayer *textureLayer );
    ~Private();

    void updateCoordinates();
};

EditGroundOverlayDialog::Private::Private( GeoDataGroundOverlay *overlay, TextureLayer *textureLayer ) :
    Ui::UiEditGroundOverlayDialog(),
    m_overlay( overlay ),
    m_textureLayer( textureLayer )
{
    // nothing to do
}

EditGroundOverlayDialog::Private::~Private()
{
    // nothing to do
}

EditGroundOverlayDialog::EditGroundOverlayDialog( GeoDataGroundOverlay *overlay,
                                                  TextureLayer *textureLayer,
                                                  QWidget *parent ) :
    QDialog( parent ),
    d( new Private( overlay, textureLayer ) )
{
    d->setupUi( this );

    d->m_header->setName( overlay->name() );
    d->m_header->setIconLink( overlay->absoluteIconFile() );
    d->m_header->setPositionVisible(false);
    d->m_description->setText( overlay->description() );

    d->m_north->setRange( -90, 90 );
    d->m_south->setRange( -90, 90 );
    d->m_west->setRange( -180, 180 );
    d->m_east->setRange( -180, 180 );
    d->m_rotation->setRange( -360, 360 );

    GeoDataLatLonBox latLonBox = overlay->latLonBox();
    d->m_north->setValue( latLonBox.north( GeoDataCoordinates::Degree ) );
    d->m_south->setValue( latLonBox.south( GeoDataCoordinates::Degree ) );
    d->m_west->setValue( latLonBox.west( GeoDataCoordinates::Degree ) );
    d->m_east->setValue( latLonBox.east( GeoDataCoordinates::Degree ) );
    d->m_rotation->setValue( latLonBox.rotation( GeoDataCoordinates::Degree ) );

    connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) );
}

EditGroundOverlayDialog::~EditGroundOverlayDialog()
{
    delete d;
}

void EditGroundOverlayDialog::updateGroundOverlay()
{
    d->m_overlay->setName( d->m_header->name() );
    d->m_overlay->setIconFile( d->m_header->iconLink() );
    d->m_overlay->setDescription( d->m_description->toPlainText() );

    d->m_overlay->latLonBox().setBoundaries( d->m_north->value(),
                                             d->m_south->value(),
                                             d->m_east->value(),
                                             d->m_west->value(),
                                             GeoDataCoordinates::Degree  );

    d->m_overlay->latLonBox().setRotation( d->m_rotation->value(), GeoDataCoordinates::Degree );
}

void EditGroundOverlayDialog::setGroundOverlayUpdated()
{
    emit groundOverlayUpdated( d->m_overlay );
}

void EditGroundOverlayDialog::checkFields()
{
    if ( d->m_header->name().isEmpty() ) {
        QMessageBox::warning( this,
                              tr( "No name specified" ),
                              tr( "Please specify a name for this ground overlay." ) );
    } else if ( d->m_header->iconLink().isEmpty() ) {
        QMessageBox::warning( this,
                              tr( "No image specified" ),
                              tr( "Please specify an image file." ) );
    } else if( !QFileInfo( d->m_header->iconLink() ).exists() ) {
        QMessageBox::warning( this,
                              tr( "Invalid image path" ),
                              tr( "Please specify a valid path for the image file." ) );
    } else {
        this->updateGroundOverlay();
        this->setGroundOverlayUpdated();
        d->m_textureLayer->reset();
        accept();
    }
}

}

#include "EditGroundOverlayDialog.moc"
<|endoftext|>


<commit_before>#include "catch/catch.hpp"
#include "RaZ/Math/Matrix.hpp"
#include "RaZ/Math/Vector.hpp"

namespace {

// Declaring vectors to be tested
const Raz::Vec3f vec31({ 3.18f, 42.f, 0.874f });
const Raz::Vec3f vec32({ 541.41f, 47.25f, 6.321f });

const Raz::Vec4f vec41({ 84.47f, 2.f, 0.001f, 847.12f });
const Raz::Vec4f vec42({ 13.01f, 0.15f, 84.8f, 72.f });

// Near-equality floating point check
template <typename T>
bool compareFloatingPoint(T val1, T val2) {
  static_assert(std::is_floating_point<T>::value, "Error: Values' type must be floating point.");

  return std::abs(val1 - val2) <= std::numeric_limits<T>::epsilon() * std::max({ static_cast<T>(1), std::abs(val1), std::abs(val2) });
}

} // namespace

TEST_CASE("Vector near-equality") {
  REQUIRE_FALSE(vec31 == vec32);

  const Raz::Vec3f baseVec(1.f);
  Raz::Vec3f compVec = baseVec;

  REQUIRE(baseVec[0] == compVec[0]); // Copied, strict equality
  REQUIRE(baseVec[1] == compVec[1]);
  REQUIRE(baseVec[2] == compVec[2]);

  compVec += 0.0000001f; // Adding a tiny offset

  REQUIRE_FALSE(baseVec[0] == compVec[0]); // Values not strictly equal
  REQUIRE_FALSE(baseVec[1] == compVec[1]);
  REQUIRE_FALSE(baseVec[2] == compVec[2]);

  REQUIRE(compareFloatingPoint(baseVec[0], compVec[0])); // Near-equality components check
  REQUIRE(compareFloatingPoint(baseVec[1], compVec[1]));
  REQUIRE(compareFloatingPoint(baseVec[2], compVec[2]));

  REQUIRE(baseVec == compVec); // Vector::operator== does a near-equality check on floating point types
}

TEST_CASE("Vector/scalar operations") {
  REQUIRE((vec31 * 3.f) == Raz::Vec3f({ 9.54f, 126.f, 2.622f }));
  REQUIRE((vec31 * 4.152f) == Raz::Vec3f({ 13.20336f, 174.384f, 3.628848f }));

  REQUIRE((vec41 * 7.5f) == Raz::Vec4f({ 633.525f, 15.f, 0.0075f, 6353.4f }));
  REQUIRE((vec41 * 8.0002f) == Raz::Vec4f({ 675.776894f, 16.0004f, 0.0080002f, 6777.129424f }));
  REQUIRE((vec41 * 0.f) == Raz::Vec4f({ 0.f, 0.f, 0.f, 0.f }));
}

TEST_CASE("Vector/vector operations") {
  REQUIRE((vec31 - vec31) == Raz::Vec3f(0.f));
  REQUIRE((vec31 * vec32) == Raz::Vec3f({ 1721.6838f, 1984.5f, 5.524554f }));

  REQUIRE(vec31.dot(vec31) == vec31.computeSquaredLength());
  REQUIRE(compareFloatingPoint(vec31.dot(vec31), 1774.876276f));
  REQUIRE(compareFloatingPoint(vec31.dot(vec32), 3711.708354f));
  REQUIRE(vec31.dot(vec32) == vec32.dot(vec31)); // A · B == B · A

  REQUIRE(vec31.cross(vec32) == Raz::Vec3f({ 224.1855f, 453.09156f, -22588.965f }));
  REQUIRE(vec31.cross(vec32) == -vec32.cross(vec31)); // A x B == -(B x A)
}

TEST_CASE("Vector/matrix operation") {
  const Raz::Mat3f mat3({{ 4.12f,  25.1f, 30.7842f },
                         { 3.04f,    5.f,   -64.5f },
                         {  -1.f, -7.54f,    8.41f }});
  REQUIRE((vec31 * mat3) == Raz::Vec3f({ 139.9076f, 283.22804f, -2603.755904f }));
  REQUIRE((vec32 * mat3) == Raz::Vec3f({ 2367.9282f, 13'777.980'66f, 13'672.408'332f }));

  const Raz::Mat4f mat4({{  -3.2f, 53.032f,  832.451f,   74.2f },
                         { 10.01f,   3.15f,   -91.41f, 187.46f },
                         {   -6.f,  -7.78f,      90.f,    38.f },
                         {  123.f,  -74.8f, 147.0001f,  748.6f }});
  REQUIRE((vec41 * mat4) == Raz::Vec4f({ 103'945.47f, -58878.67074f, 194'661.130'682f, 640'796.664f }));
  REQUIRE((vec42 * mat4) == Raz::Vec4f({ 8307.0695f, -5354.92518f, 29032.48321f, 58115.061f }));

  REQUIRE((vec31 * Raz::Mat3f::identity()) == vec31);
  REQUIRE((vec41 * Raz::Mat4f::identity()) == vec41);
}

TEST_CASE("Vector manipulations") {
  REQUIRE(compareFloatingPoint(vec31.normalize().computeLength(), 1.f));
  REQUIRE(compareFloatingPoint(vec41.normalize().computeSquaredLength(), 1.f));
  REQUIRE(compareFloatingPoint(Raz::Vec3f({ 0.f, 1.f, 0.f }).computeLength(), 1.f));

  // Testing Vector::reflect():
  //
  // IncVec  N  Reflection
  //     \   |   /
  //      \  |  /
  //       \ | /
  //________\|/___________
  //
  REQUIRE(Raz::Vec3f({ 1.f, -1.f, 0.f }).reflect(Raz::Vec3f({ 0.f, 1.f, 0.f })) == Raz::Vec3f({ 1.f, 1.f, 0.f }));
  REQUIRE(vec31.reflect(Raz::Vec3f({ 0.f, 1.f, 0.f })) == Raz::Vec3f({ 3.18f, -42.f, 0.874f }));
  REQUIRE(vec31.reflect(vec32) == Raz::Vec3f({ -4'019'108.859'878'28f, -350'714.439'453f, -46'922.543'011'268f }));
}
<commit_msg>[Update] Vector tests now make use of FloatUtils::checkNearEquality()<commit_after>#include "catch/catch.hpp"
#include "RaZ/Math/Matrix.hpp"
#include "RaZ/Math/Vector.hpp"
#include "RaZ/Utils/FloatUtils.hpp"

namespace {

// Declaring vectors to be tested
const Raz::Vec3f vec31({ 3.18f, 42.f, 0.874f });
const Raz::Vec3f vec32({ 541.41f, 47.25f, 6.321f });

const Raz::Vec4f vec41({ 84.47f, 2.f, 0.001f, 847.12f });
const Raz::Vec4f vec42({ 13.01f, 0.15f, 84.8f, 72.f });

} // namespace

TEST_CASE("Vector near-equality") {
  REQUIRE_FALSE(vec31 == vec32);

  const Raz::Vec3f baseVec(1.f);
  Raz::Vec3f compVec = baseVec;

  REQUIRE(baseVec[0] == compVec[0]); // Copied, strict equality
  REQUIRE(baseVec[1] == compVec[1]);
  REQUIRE(baseVec[2] == compVec[2]);

  compVec += 0.0000001f; // Adding a tiny offset

  REQUIRE_FALSE(baseVec[0] == compVec[0]); // Values not strictly equal
  REQUIRE_FALSE(baseVec[1] == compVec[1]);
  REQUIRE_FALSE(baseVec[2] == compVec[2]);

  REQUIRE(Raz::FloatUtils::checkNearEquality(baseVec[0], compVec[0])); // Near-equality components check
  REQUIRE(Raz::FloatUtils::checkNearEquality(baseVec[1], compVec[1]));
  REQUIRE(Raz::FloatUtils::checkNearEquality(baseVec[2], compVec[2]));

  REQUIRE(baseVec == compVec); // Vector::operator== does a near-equality check on floating point types
}

TEST_CASE("Vector/scalar operations") {
  REQUIRE((vec31 * 3.f) == Raz::Vec3f({ 9.54f, 126.f, 2.622f }));
  REQUIRE((vec31 * 4.152f) == Raz::Vec3f({ 13.20336f, 174.384f, 3.628848f }));

  REQUIRE((vec41 * 7.5f) == Raz::Vec4f({ 633.525f, 15.f, 0.0075f, 6353.4f }));
  REQUIRE((vec41 * 8.0002f) == Raz::Vec4f({ 675.776894f, 16.0004f, 0.0080002f, 6777.129424f }));
  REQUIRE((vec41 * 0.f) == Raz::Vec4f({ 0.f, 0.f, 0.f, 0.f }));
}

TEST_CASE("Vector/vector operations") {
  REQUIRE((vec31 - vec31) == Raz::Vec3f(0.f));
  REQUIRE((vec31 * vec32) == Raz::Vec3f({ 1721.6838f, 1984.5f, 5.524554f }));

  REQUIRE(vec31.dot(vec31) == vec31.computeSquaredLength());
  REQUIRE(Raz::FloatUtils::checkNearEquality(vec31.dot(vec31), 1774.876276f));
  REQUIRE(Raz::FloatUtils::checkNearEquality(vec31.dot(vec32), 3711.708354f));
  REQUIRE(vec31.dot(vec32) == vec32.dot(vec31)); // A · B == B · A

  REQUIRE(vec31.cross(vec32) == Raz::Vec3f({ 224.1855f, 453.09156f, -22588.965f }));
  REQUIRE(vec31.cross(vec32) == -vec32.cross(vec31)); // A x B == -(B x A)
}

TEST_CASE("Vector/matrix operation") {
  const Raz::Mat3f mat3({{ 4.12f,  25.1f, 30.7842f },
                         { 3.04f,    5.f,   -64.5f },
                         {  -1.f, -7.54f,    8.41f }});
  REQUIRE((vec31 * mat3) == Raz::Vec3f({ 139.9076f, 283.22804f, -2603.755904f }));
  REQUIRE((vec32 * mat3) == Raz::Vec3f({ 2367.9282f, 13'777.980'66f, 13'672.408'332f }));

  const Raz::Mat4f mat4({{  -3.2f, 53.032f,  832.451f,   74.2f },
                         { 10.01f,   3.15f,   -91.41f, 187.46f },
                         {   -6.f,  -7.78f,      90.f,    38.f },
                         {  123.f,  -74.8f, 147.0001f,  748.6f }});
  REQUIRE((vec41 * mat4) == Raz::Vec4f({ 103'945.47f, -58878.67074f, 194'661.130'682f, 640'796.664f }));
  REQUIRE((vec42 * mat4) == Raz::Vec4f({ 8307.0695f, -5354.92518f, 29032.48321f, 58115.061f }));

  REQUIRE((vec31 * Raz::Mat3f::identity()) == vec31);
  REQUIRE((vec41 * Raz::Mat4f::identity()) == vec41);
}

TEST_CASE("Vector manipulations") {
  REQUIRE(Raz::FloatUtils::checkNearEquality(vec31.normalize().computeLength(), 1.f));
  REQUIRE(Raz::FloatUtils::checkNearEquality(vec41.normalize().computeSquaredLength(), 1.f));
  REQUIRE(Raz::FloatUtils::checkNearEquality(Raz::Vec3f({ 0.f, 1.f, 0.f }).computeLength(), 1.f));

  // Testing Vector::reflect():
  //
  // IncVec  N  Reflection
  //     \   |   /
  //      \  |  /
  //       \ | /
  //________\|/___________
  //
  REQUIRE(Raz::Vec3f({ 1.f, -1.f, 0.f }).reflect(Raz::Vec3f({ 0.f, 1.f, 0.f })) == Raz::Vec3f({ 1.f, 1.f, 0.f }));
  REQUIRE(vec31.reflect(Raz::Vec3f({ 0.f, 1.f, 0.f })) == Raz::Vec3f({ 3.18f, -42.f, 0.874f }));
  REQUIRE(vec31.reflect(vec32) == Raz::Vec3f({ -4'019'108.859'878'28f, -350'714.439'453f, -46'922.543'011'268f }));
}
<|endoftext|>


<commit_before>//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/NativeFormatting.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"

using namespace llvm;

template<typename T, std::size_t N>
static int format_to_buffer(T Value, char (&Buffer)[N]) {
  char *EndPtr = std::end(Buffer);
  char *CurPtr = EndPtr;

  do {
    *--CurPtr = '0' + char(Value % 10);
    Value /= 10;
  } while (Value);
  return EndPtr - CurPtr;
}

static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
  assert(!Buffer.empty());

  ArrayRef<char> ThisGroup;
  int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
  ThisGroup = Buffer.take_front(InitialDigits);
  S.write(ThisGroup.data(), ThisGroup.size());

  Buffer = Buffer.drop_front(InitialDigits);
  assert(Buffer.size() % 3 == 0);
  while (!Buffer.empty()) {
    S << ',';
    ThisGroup = Buffer.take_front(3);
    S.write(ThisGroup.data(), 3);
    Buffer = Buffer.drop_front(3);
  }
}

template <typename T>
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
                                IntegerStyle Style, bool IsNegative) {
  static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");

  char NumberBuffer[128];
  std::memset(NumberBuffer, '0', sizeof(NumberBuffer));

  size_t Len = 0;
  Len = format_to_buffer(N, NumberBuffer);

  if (IsNegative)
    S << '-';

  if (Len < MinDigits && Style != IntegerStyle::Number) {
    for (size_t I = Len; I < MinDigits; ++I)
      S << '0';
  }

  if (Style == IntegerStyle::Number) {
    writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
  } else {
    S.write(std::end(NumberBuffer) - Len, Len);
  }
}

template <typename T>
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
                           IntegerStyle Style, bool IsNegative = false) {
  // Output using 32-bit div/mod if possible.
  if (N == static_cast<uint32_t>(N))
    write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
                        IsNegative);
  else
    write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
}

template <typename T>
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
                         IntegerStyle Style) {
  static_assert(std::is_signed<T>::value, "Value is not signed!");

  using UnsignedT = typename std::make_unsigned<T>::type;

  if (N >= 0) {
    write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
    return;
  }

  UnsignedT UN = -(UnsignedT)N;
  write_unsigned(S, UN, MinDigits, Style, true);
}

void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
                     Optional<size_t> Width) {
  const size_t kMaxWidth = 128u;

  size_t W = std::min(kMaxWidth, Width.getValueOr(0u));

  unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
  bool Prefix = (Style == HexPrintStyle::PrefixLower ||
                 Style == HexPrintStyle::PrefixUpper);
  bool Upper =
      (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
  unsigned PrefixChars = Prefix ? 2 : 0;
  unsigned NumChars =
      std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);

  char NumberBuffer[kMaxWidth];
  ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
  if (Prefix)
    NumberBuffer[1] = 'x';
  char *EndPtr = NumberBuffer + NumChars;
  char *CurPtr = EndPtr;
  while (N) {
    unsigned char x = static_cast<unsigned char>(N) % 16;
    *--CurPtr = hexdigit(x, !Upper);
    N /= 16;
  }

  S.write(NumberBuffer, NumChars);
}

void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
                        Optional<size_t> Precision) {
  size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));

  if (std::isnan(N)) {
    S << "nan";
    return;
  } else if (std::isinf(N)) {
    S << "INF";
    return;
  }

  char Letter;
  if (Style == FloatStyle::Exponent)
    Letter = 'e';
  else if (Style == FloatStyle::ExponentUpper)
    Letter = 'E';
  else
    Letter = 'f';

  SmallString<8> Spec;
  llvm::raw_svector_ostream Out(Spec);
  Out << "%." << Prec << Letter;

  if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
#ifdef _WIN32
// On MSVCRT and compatible, output of %e is incompatible to Posix
// by default. Number of exponent digits should be at least 2. "%+03d"
// FIXME: Implement our formatter to here or Support/Format.h!
#if defined(__MINGW32__)
    // FIXME: It should be generic to C++11.
    if (N == 0.0 && std::signbit(N)) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#else
    int fpcl = _fpclass(N);

    // negative zero
    if (fpcl == _FPCLASS_NZ) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#endif

    char buf[32];
    unsigned len;
    len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
    if (len <= sizeof(buf) - 2) {
      if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
          buf[len - 3] == '0') {
        int cs = buf[len - 4];
        if (cs == '+' || cs == '-') {
          int c1 = buf[len - 2];
          int c0 = buf[len - 1];
          if (isdigit(static_cast<unsigned char>(c1)) &&
              isdigit(static_cast<unsigned char>(c0))) {
            // Trim leading '0': "...e+012" -> "...e+12\0"
            buf[len - 3] = c1;
            buf[len - 2] = c0;
            buf[--len] = 0;
          }
        }
      }
      S << buf;
      return;
    }
#endif
  }

  if (Style == FloatStyle::Percent)
    N *= 100.0;

  char Buf[32];
  unsigned Len;
  Len = format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
  if (Style == FloatStyle::Percent)
    ++Len;
  S << Buf;
  if (Style == FloatStyle::Percent)
    S << '%';
}

bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
  return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
}

size_t llvm::getDefaultPrecision(FloatStyle Style) {
  switch (Style) {
  case FloatStyle::Exponent:
  case FloatStyle::ExponentUpper:
    return 6; // Number of decimal places.
  case FloatStyle::Fixed:
  case FloatStyle::Percent:
    return 2; // Number of decimal places.
  }
  LLVM_BUILTIN_UNREACHABLE;
}
<commit_msg>Remove dead variable Len.<commit_after>//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/NativeFormatting.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"

using namespace llvm;

template<typename T, std::size_t N>
static int format_to_buffer(T Value, char (&Buffer)[N]) {
  char *EndPtr = std::end(Buffer);
  char *CurPtr = EndPtr;

  do {
    *--CurPtr = '0' + char(Value % 10);
    Value /= 10;
  } while (Value);
  return EndPtr - CurPtr;
}

static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
  assert(!Buffer.empty());

  ArrayRef<char> ThisGroup;
  int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
  ThisGroup = Buffer.take_front(InitialDigits);
  S.write(ThisGroup.data(), ThisGroup.size());

  Buffer = Buffer.drop_front(InitialDigits);
  assert(Buffer.size() % 3 == 0);
  while (!Buffer.empty()) {
    S << ',';
    ThisGroup = Buffer.take_front(3);
    S.write(ThisGroup.data(), 3);
    Buffer = Buffer.drop_front(3);
  }
}

template <typename T>
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
                                IntegerStyle Style, bool IsNegative) {
  static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");

  char NumberBuffer[128];
  std::memset(NumberBuffer, '0', sizeof(NumberBuffer));

  size_t Len = 0;
  Len = format_to_buffer(N, NumberBuffer);

  if (IsNegative)
    S << '-';

  if (Len < MinDigits && Style != IntegerStyle::Number) {
    for (size_t I = Len; I < MinDigits; ++I)
      S << '0';
  }

  if (Style == IntegerStyle::Number) {
    writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
  } else {
    S.write(std::end(NumberBuffer) - Len, Len);
  }
}

template <typename T>
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
                           IntegerStyle Style, bool IsNegative = false) {
  // Output using 32-bit div/mod if possible.
  if (N == static_cast<uint32_t>(N))
    write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
                        IsNegative);
  else
    write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
}

template <typename T>
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
                         IntegerStyle Style) {
  static_assert(std::is_signed<T>::value, "Value is not signed!");

  using UnsignedT = typename std::make_unsigned<T>::type;

  if (N >= 0) {
    write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
    return;
  }

  UnsignedT UN = -(UnsignedT)N;
  write_unsigned(S, UN, MinDigits, Style, true);
}

void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_unsigned(S, N, MinDigits, Style);
}

void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
                         IntegerStyle Style) {
  write_signed(S, N, MinDigits, Style);
}

void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
                     Optional<size_t> Width) {
  const size_t kMaxWidth = 128u;

  size_t W = std::min(kMaxWidth, Width.getValueOr(0u));

  unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
  bool Prefix = (Style == HexPrintStyle::PrefixLower ||
                 Style == HexPrintStyle::PrefixUpper);
  bool Upper =
      (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
  unsigned PrefixChars = Prefix ? 2 : 0;
  unsigned NumChars =
      std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);

  char NumberBuffer[kMaxWidth];
  ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
  if (Prefix)
    NumberBuffer[1] = 'x';
  char *EndPtr = NumberBuffer + NumChars;
  char *CurPtr = EndPtr;
  while (N) {
    unsigned char x = static_cast<unsigned char>(N) % 16;
    *--CurPtr = hexdigit(x, !Upper);
    N /= 16;
  }

  S.write(NumberBuffer, NumChars);
}

void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
                        Optional<size_t> Precision) {
  size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));

  if (std::isnan(N)) {
    S << "nan";
    return;
  } else if (std::isinf(N)) {
    S << "INF";
    return;
  }

  char Letter;
  if (Style == FloatStyle::Exponent)
    Letter = 'e';
  else if (Style == FloatStyle::ExponentUpper)
    Letter = 'E';
  else
    Letter = 'f';

  SmallString<8> Spec;
  llvm::raw_svector_ostream Out(Spec);
  Out << "%." << Prec << Letter;

  if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
#ifdef _WIN32
// On MSVCRT and compatible, output of %e is incompatible to Posix
// by default. Number of exponent digits should be at least 2. "%+03d"
// FIXME: Implement our formatter to here or Support/Format.h!
#if defined(__MINGW32__)
    // FIXME: It should be generic to C++11.
    if (N == 0.0 && std::signbit(N)) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#else
    int fpcl = _fpclass(N);

    // negative zero
    if (fpcl == _FPCLASS_NZ) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#endif

    char buf[32];
    unsigned len;
    len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
    if (len <= sizeof(buf) - 2) {
      if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
          buf[len - 3] == '0') {
        int cs = buf[len - 4];
        if (cs == '+' || cs == '-') {
          int c1 = buf[len - 2];
          int c0 = buf[len - 1];
          if (isdigit(static_cast<unsigned char>(c1)) &&
              isdigit(static_cast<unsigned char>(c0))) {
            // Trim leading '0': "...e+012" -> "...e+12\0"
            buf[len - 3] = c1;
            buf[len - 2] = c0;
            buf[--len] = 0;
          }
        }
      }
      S << buf;
      return;
    }
#endif
  }

  if (Style == FloatStyle::Percent)
    N *= 100.0;

  char Buf[32];
  format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
  S << Buf;
  if (Style == FloatStyle::Percent)
    S << '%';
}

bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
  return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
}

size_t llvm::getDefaultPrecision(FloatStyle Style) {
  switch (Style) {
  case FloatStyle::Exponent:
  case FloatStyle::ExponentUpper:
    return 6; // Number of decimal places.
  case FloatStyle::Fixed:
  case FloatStyle::Percent:
    return 2; // Number of decimal places.
  }
  LLVM_BUILTIN_UNREACHABLE;
}
<|endoftext|>


<commit_before>//===- Darwin/MappedFile.cpp - Darwin MappedFile Implementation -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides the Darwin specific implementation of the MappedFile
// concept.
//
//===----------------------------------------------------------------------===//

// Include the generic unix implementation
#include "../Unix/MappedFile.cpp"

// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
<commit_msg>Allow this file to compile on Darwin.<commit_after>//===- Darwin/MappedFile.cpp - Darwin MappedFile Implementation -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides the Darwin specific implementation of the MappedFile
// concept.
//
//===----------------------------------------------------------------------===//

// Include the generic unix implementation
#include <sys/stat.h>
#include "../Unix/MappedFile.cpp"

// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
<|endoftext|>


<commit_before>//===- BuildTree.cpp ------------------------------------------*- C++ -*-=====//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/BuildTree.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <map>

using namespace clang;

/// A helper class for constructing the syntax tree while traversing a clang
/// AST.
///
/// At each point of the traversal we maintain a list of pending nodes.
/// Initially all tokens are added as pending nodes. When processing a clang AST
/// node, the clients need to:
///   - create a corresponding syntax node,
///   - assign roles to all pending child nodes with 'markChild' and
///     'markChildToken',
///   - replace the child nodes with the new syntax node in the pending list
///     with 'foldNode'.
///
/// Note that all children are expected to be processed when building a node.
///
/// Call finalize() to finish building the tree and consume the root node.
class syntax::TreeBuilder {
public:
  TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {}

  llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }

  /// Populate children for \p New node, assuming it covers tokens from \p
  /// Range.
  void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New);

  /// Set role for a token starting at \p Loc.
  void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R);

  /// Finish building the tree and consume the root node.
  syntax::TranslationUnit *finalize() && {
    auto Tokens = Arena.tokenBuffer().expandedTokens();
    // Build the root of the tree, consuming all the children.
    Pending.foldChildren(Tokens,
                         new (Arena.allocator()) syntax::TranslationUnit);

    return cast<syntax::TranslationUnit>(std::move(Pending).finalize());
  }

  /// getRange() finds the syntax tokens corresponding to the passed source
  /// locations.
  /// \p First is the start position of the first token and \p Last is the start
  /// position of the last token.
  llvm::ArrayRef<syntax::Token> getRange(SourceLocation First,
                                         SourceLocation Last) const {
    assert(First.isValid());
    assert(Last.isValid());
    assert(First == Last ||
           Arena.sourceManager().isBeforeInTranslationUnit(First, Last));
    return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
  }
  llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const {
    return getRange(D->getBeginLoc(), D->getEndLoc());
  }
  llvm::ArrayRef<syntax::Token> getRange(const Stmt *S) const {
    return getRange(S->getBeginLoc(), S->getEndLoc());
  }

private:
  /// Finds a token starting at \p L. The token must exist.
  const syntax::Token *findToken(SourceLocation L) const;

  /// A collection of trees covering the input tokens.
  /// When created, each tree corresponds to a single token in the file.
  /// Clients call 'foldChildren' to attach one or more subtrees to a parent
  /// node and update the list of trees accordingly.
  ///
  /// Ensures that added nodes properly nest and cover the whole token stream.
  struct Forest {
    Forest(syntax::Arena &A) {
      // FIXME: do not add 'eof' to the tree.

      // Create all leaf nodes.
      for (auto &T : A.tokenBuffer().expandedTokens())
        Trees.insert(Trees.end(),
                     {&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}});
    }

    void assignRole(llvm::ArrayRef<syntax::Token> Range,
                    syntax::NodeRole Role) {
      assert(!Range.empty());
      auto It = Trees.lower_bound(Range.begin());
      assert(It != Trees.end() && "no node found");
      assert(It->first == Range.begin() && "no child with the specified range");
      assert(std::next(It) == Trees.end() ||
             std::next(It)->first == Range.end() &&
                 "no child with the specified range");
      It->second.Role = Role;
    }

    /// Add \p Node to the forest and fill its children nodes based on the \p
    /// NodeRange.
    void foldChildren(llvm::ArrayRef<syntax::Token> NodeTokens,
                      syntax::Tree *Node) {
      assert(!NodeTokens.empty());
      assert(Node->firstChild() == nullptr && "node already has children");

      auto *FirstToken = NodeTokens.begin();
      auto BeginChildren = Trees.lower_bound(FirstToken);
      assert(BeginChildren != Trees.end() &&
             BeginChildren->first == FirstToken &&
             "fold crosses boundaries of existing subtrees");
      auto EndChildren = Trees.lower_bound(NodeTokens.end());
      assert(EndChildren == Trees.end() ||
             EndChildren->first == NodeTokens.end() &&
                 "fold crosses boundaries of existing subtrees");

      // (!) we need to go in reverse order, because we can only prepend.
      for (auto It = EndChildren; It != BeginChildren; --It)
        Node->prependChildLowLevel(std::prev(It)->second.Node,
                                   std::prev(It)->second.Role);

      Trees.erase(BeginChildren, EndChildren);
      Trees.insert({FirstToken, NodeAndRole(Node)});
    }

    // EXPECTS: all tokens were consumed and are owned by a single root node.
    syntax::Node *finalize() && {
      assert(Trees.size() == 1);
      auto *Root = Trees.begin()->second.Node;
      Trees = {};
      return Root;
    }

    std::string str(const syntax::Arena &A) const {
      std::string R;
      for (auto It = Trees.begin(); It != Trees.end(); ++It) {
        unsigned CoveredTokens =
            It != Trees.end()
                ? (std::next(It)->first - It->first)
                : A.tokenBuffer().expandedTokens().end() - It->first;

        R += llvm::formatv("- '{0}' covers '{1}'+{2} tokens\n",
                           It->second.Node->kind(),
                           It->first->text(A.sourceManager()), CoveredTokens);
        R += It->second.Node->dump(A);
      }
      return R;
    }

  private:
    /// A with a role that should be assigned to it when adding to a parent.
    struct NodeAndRole {
      explicit NodeAndRole(syntax::Node *Node)
          : Node(Node), Role(NodeRoleUnknown) {}

      syntax::Node *Node;
      NodeRole Role;
    };

    /// Maps from the start token to a subtree starting at that token.
    /// FIXME: storing the end tokens is redundant.
    /// FIXME: the key of a map is redundant, it is also stored in NodeForRange.
    std::map<const syntax::Token *, NodeAndRole> Trees;
  };

  /// For debugging purposes.
  std::string str() { return Pending.str(Arena); }

  syntax::Arena &Arena;
  Forest Pending;
};

namespace {
class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
public:
  explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder)
      : Builder(Builder), LangOpts(Ctx.getLangOpts()) {}

  bool shouldTraversePostOrder() const { return true; }

  bool TraverseDecl(Decl *D) {
    if (!D || isa<TranslationUnitDecl>(D))
      return RecursiveASTVisitor::TraverseDecl(D);
    if (!llvm::isa<TranslationUnitDecl>(D->getDeclContext()))
      return true; // Only build top-level decls for now, do not recurse.
    return RecursiveASTVisitor::TraverseDecl(D);
  }

  bool VisitDecl(Decl *D) {
    assert(llvm::isa<TranslationUnitDecl>(D->getDeclContext()) &&
           "expected a top-level decl");
    assert(!D->isImplicit());
    Builder.foldNode(Builder.getRange(D),
                     new (allocator()) syntax::TopLevelDeclaration());
    return true;
  }

  bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) {
    // (!) we do not want to call VisitDecl(), the declaration for translation
    // unit is built by finalize().
    return true;
  }

  bool WalkUpFromCompoundStmt(CompoundStmt *S) {
    using Roles = syntax::CompoundStatement::Roles;

    Builder.markChildToken(S->getLBracLoc(), tok::l_brace, Roles::lbrace);
    Builder.markChildToken(S->getRBracLoc(), tok::r_brace, Roles::rbrace);

    Builder.foldNode(Builder.getRange(S),
                     new (allocator()) syntax::CompoundStatement);
    return true;
  }

private:
  /// A small helper to save some typing.
  llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }

  syntax::TreeBuilder &Builder;
  const LangOptions &LangOpts;
};
} // namespace

void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range,
                                   syntax::Tree *New) {
  Pending.foldChildren(Range, New);
}

void syntax::TreeBuilder::markChildToken(SourceLocation Loc,
                                         tok::TokenKind Kind, NodeRole Role) {
  if (Loc.isInvalid())
    return;
  Pending.assignRole(*findToken(Loc), Role);
}

const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const {
  auto Tokens = Arena.tokenBuffer().expandedTokens();
  auto &SM = Arena.sourceManager();
  auto It = llvm::partition_point(Tokens, [&](const syntax::Token &T) {
    return SM.isBeforeInTranslationUnit(T.location(), L);
  });
  assert(It != Tokens.end());
  assert(It->location() == L);
  return &*It;
}

syntax::TranslationUnit *
syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) {
  TreeBuilder Builder(A);
  BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext());
  return std::move(Builder).finalize();
}
<commit_msg>Add parentheses to silence warnings.<commit_after>//===- BuildTree.cpp ------------------------------------------*- C++ -*-=====//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/BuildTree.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <map>

using namespace clang;

/// A helper class for constructing the syntax tree while traversing a clang
/// AST.
///
/// At each point of the traversal we maintain a list of pending nodes.
/// Initially all tokens are added as pending nodes. When processing a clang AST
/// node, the clients need to:
///   - create a corresponding syntax node,
///   - assign roles to all pending child nodes with 'markChild' and
///     'markChildToken',
///   - replace the child nodes with the new syntax node in the pending list
///     with 'foldNode'.
///
/// Note that all children are expected to be processed when building a node.
///
/// Call finalize() to finish building the tree and consume the root node.
class syntax::TreeBuilder {
public:
  TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {}

  llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }

  /// Populate children for \p New node, assuming it covers tokens from \p
  /// Range.
  void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New);

  /// Set role for a token starting at \p Loc.
  void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R);

  /// Finish building the tree and consume the root node.
  syntax::TranslationUnit *finalize() && {
    auto Tokens = Arena.tokenBuffer().expandedTokens();
    // Build the root of the tree, consuming all the children.
    Pending.foldChildren(Tokens,
                         new (Arena.allocator()) syntax::TranslationUnit);

    return cast<syntax::TranslationUnit>(std::move(Pending).finalize());
  }

  /// getRange() finds the syntax tokens corresponding to the passed source
  /// locations.
  /// \p First is the start position of the first token and \p Last is the start
  /// position of the last token.
  llvm::ArrayRef<syntax::Token> getRange(SourceLocation First,
                                         SourceLocation Last) const {
    assert(First.isValid());
    assert(Last.isValid());
    assert(First == Last ||
           Arena.sourceManager().isBeforeInTranslationUnit(First, Last));
    return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
  }
  llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const {
    return getRange(D->getBeginLoc(), D->getEndLoc());
  }
  llvm::ArrayRef<syntax::Token> getRange(const Stmt *S) const {
    return getRange(S->getBeginLoc(), S->getEndLoc());
  }

private:
  /// Finds a token starting at \p L. The token must exist.
  const syntax::Token *findToken(SourceLocation L) const;

  /// A collection of trees covering the input tokens.
  /// When created, each tree corresponds to a single token in the file.
  /// Clients call 'foldChildren' to attach one or more subtrees to a parent
  /// node and update the list of trees accordingly.
  ///
  /// Ensures that added nodes properly nest and cover the whole token stream.
  struct Forest {
    Forest(syntax::Arena &A) {
      // FIXME: do not add 'eof' to the tree.

      // Create all leaf nodes.
      for (auto &T : A.tokenBuffer().expandedTokens())
        Trees.insert(Trees.end(),
                     {&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}});
    }

    void assignRole(llvm::ArrayRef<syntax::Token> Range,
                    syntax::NodeRole Role) {
      assert(!Range.empty());
      auto It = Trees.lower_bound(Range.begin());
      assert(It != Trees.end() && "no node found");
      assert(It->first == Range.begin() && "no child with the specified range");
      assert((std::next(It) == Trees.end() ||
              std::next(It)->first == Range.end()) &&
             "no child with the specified range");
      It->second.Role = Role;
    }

    /// Add \p Node to the forest and fill its children nodes based on the \p
    /// NodeRange.
    void foldChildren(llvm::ArrayRef<syntax::Token> NodeTokens,
                      syntax::Tree *Node) {
      assert(!NodeTokens.empty());
      assert(Node->firstChild() == nullptr && "node already has children");

      auto *FirstToken = NodeTokens.begin();
      auto BeginChildren = Trees.lower_bound(FirstToken);
      assert(BeginChildren != Trees.end() &&
             BeginChildren->first == FirstToken &&
             "fold crosses boundaries of existing subtrees");
      auto EndChildren = Trees.lower_bound(NodeTokens.end());
      assert((EndChildren == Trees.end() ||
              EndChildren->first == NodeTokens.end()) &&
             "fold crosses boundaries of existing subtrees");

      // (!) we need to go in reverse order, because we can only prepend.
      for (auto It = EndChildren; It != BeginChildren; --It)
        Node->prependChildLowLevel(std::prev(It)->second.Node,
                                   std::prev(It)->second.Role);

      Trees.erase(BeginChildren, EndChildren);
      Trees.insert({FirstToken, NodeAndRole(Node)});
    }

    // EXPECTS: all tokens were consumed and are owned by a single root node.
    syntax::Node *finalize() && {
      assert(Trees.size() == 1);
      auto *Root = Trees.begin()->second.Node;
      Trees = {};
      return Root;
    }

    std::string str(const syntax::Arena &A) const {
      std::string R;
      for (auto It = Trees.begin(); It != Trees.end(); ++It) {
        unsigned CoveredTokens =
            It != Trees.end()
                ? (std::next(It)->first - It->first)
                : A.tokenBuffer().expandedTokens().end() - It->first;

        R += llvm::formatv("- '{0}' covers '{1}'+{2} tokens\n",
                           It->second.Node->kind(),
                           It->first->text(A.sourceManager()), CoveredTokens);
        R += It->second.Node->dump(A);
      }
      return R;
    }

  private:
    /// A with a role that should be assigned to it when adding to a parent.
    struct NodeAndRole {
      explicit NodeAndRole(syntax::Node *Node)
          : Node(Node), Role(NodeRoleUnknown) {}

      syntax::Node *Node;
      NodeRole Role;
    };

    /// Maps from the start token to a subtree starting at that token.
    /// FIXME: storing the end tokens is redundant.
    /// FIXME: the key of a map is redundant, it is also stored in NodeForRange.
    std::map<const syntax::Token *, NodeAndRole> Trees;
  };

  /// For debugging purposes.
  std::string str() { return Pending.str(Arena); }

  syntax::Arena &Arena;
  Forest Pending;
};

namespace {
class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
public:
  explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder)
      : Builder(Builder), LangOpts(Ctx.getLangOpts()) {}

  bool shouldTraversePostOrder() const { return true; }

  bool TraverseDecl(Decl *D) {
    if (!D || isa<TranslationUnitDecl>(D))
      return RecursiveASTVisitor::TraverseDecl(D);
    if (!llvm::isa<TranslationUnitDecl>(D->getDeclContext()))
      return true; // Only build top-level decls for now, do not recurse.
    return RecursiveASTVisitor::TraverseDecl(D);
  }

  bool VisitDecl(Decl *D) {
    assert(llvm::isa<TranslationUnitDecl>(D->getDeclContext()) &&
           "expected a top-level decl");
    assert(!D->isImplicit());
    Builder.foldNode(Builder.getRange(D),
                     new (allocator()) syntax::TopLevelDeclaration());
    return true;
  }

  bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) {
    // (!) we do not want to call VisitDecl(), the declaration for translation
    // unit is built by finalize().
    return true;
  }

  bool WalkUpFromCompoundStmt(CompoundStmt *S) {
    using Roles = syntax::CompoundStatement::Roles;

    Builder.markChildToken(S->getLBracLoc(), tok::l_brace, Roles::lbrace);
    Builder.markChildToken(S->getRBracLoc(), tok::r_brace, Roles::rbrace);

    Builder.foldNode(Builder.getRange(S),
                     new (allocator()) syntax::CompoundStatement);
    return true;
  }

private:
  /// A small helper to save some typing.
  llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }

  syntax::TreeBuilder &Builder;
  const LangOptions &LangOpts;
};
} // namespace

void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range,
                                   syntax::Tree *New) {
  Pending.foldChildren(Range, New);
}

void syntax::TreeBuilder::markChildToken(SourceLocation Loc,
                                         tok::TokenKind Kind, NodeRole Role) {
  if (Loc.isInvalid())
    return;
  Pending.assignRole(*findToken(Loc), Role);
}

const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const {
  auto Tokens = Arena.tokenBuffer().expandedTokens();
  auto &SM = Arena.sourceManager();
  auto It = llvm::partition_point(Tokens, [&](const syntax::Token &T) {
    return SM.isBeforeInTranslationUnit(T.location(), L);
  });
  assert(It != Tokens.end());
  assert(It->location() == L);
  return &*It;
}

syntax::TranslationUnit *
syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) {
  TreeBuilder Builder(A);
  BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext());
  return std::move(Builder).finalize();
}
<|endoftext|>