<commit_before>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#pragma once

#include "spi.h"
#include "types.hpp"
#include <stdexcept>

namespace mraa
{

/**
 * MRAA SPI Modes
 */
typedef enum {
    SPI_MODE0 = 0, /**< CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge,
                      output data (change) on falling edge */
    SPI_MODE1 = 1, /**< CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge,
                      output data (change) on rising edge */
    SPI_MODE2 = 2, /**< CPOL = 1, CPHA = 0, Clock idle low, data is clocked in on falling edge,
                      output data (change) on rising edge */
    SPI_MODE3 = 3, /**< CPOL = 1, CPHA = 1, Clock idle low, data is clocked in on rising, edge
                      output data (change) on falling edge */
} Spi_Mode;

/**
* @brief API to Serial Peripheral Interface
*
* This file defines the SPI interface for libmraa
*
* @snippet Spi-pot.cpp Interesting
*/
class Spi
{
  public:
    /**
     * Initialise SPI object using the board mapping to set muxes
     *
     * @param bus to use, as listed in the platform definition, normally 0
     */
    Spi(int bus)
    {
        m_spi = mraa_spi_init(bus);

        if (m_spi == NULL) {
            throw std::invalid_argument("Error initialising SPI bus");
        }
    }

    /**
     * Closes spi bus
     */
    ~Spi()
    {
        mraa_spi_stop(m_spi);
    }

    /**
     * Set the SPI device mode. see spidev0-3
     *
     * @param mode the mode. See Linux spidev doc
     * @return Result of operation
     */
    Result
    mode(Spi_Mode mode)
    {
        return (Result) mraa_spi_mode(m_spi, (mraa_spi_mode_t) mode);
    }

    /**
     * Set the SPI device operating clock frequency
     *
     * @param hz the frequency to set in hz
     * @return Result of operation
     */
    Result
    frequency(int hz)
    {
        return (Result) mraa_spi_frequency(m_spi, hz);
    }

    /**
     * Write single byte to the SPI device
     *
     * @param data the byte to send
     * @return data received on the miso line or -1 in case of error
     */
    int
    writeByte(uint8_t data)
    {
        return mraa_spi_write(m_spi, (uint8_t) data);
    }

    /**
     * Write single byte to the SPI device
     *
     * @param data the byte to send
     * @return data received on the miso line
     */
    uint16_t
    write_word(uint16_t data)
    {
        return mraa_spi_write_word(m_spi, (uint16_t) data);
    }

    /**
     * Write buffer of bytes to SPI device The pointer return has to be
     * free'd by the caller. It will return a NULL pointer in cases of
     * error
     *
     * @param txBuf buffer to send
     * @param length size of buffer to send
     * @return uint8_t* data received on the miso line. Same length as passed in
     */
    uint8_t*
    write(uint8_t* txBuf, int length)
    {
        return mraa_spi_write_buf(m_spi, txBuf, length);
    }

#ifndef SWIG
    /**
     * Write buffer of bytes to SPI device The pointer return has to be
     * free'd by the caller. It will return a NULL pointer in cases of
     * error
     *
     * @param txBuf buffer to send
     * @param length size of buffer (in bytes) to send
     * @return uint8_t* data received on the miso line. Same length as passed in
     */
    uint16_t*
    write_word(uint16_t* txBuf, int length)
    {
        return mraa_spi_write_buf_word(m_spi, txBuf, length);
    }
#endif

#ifndef SWIG
    /**
     * Transfer data to and from SPI device Receive pointer may be null if
     * return data is not needed.
     *
     * @param txBuf buffer to send
     * @param rxBuf buffer to optionally receive data from spi device
     * @param length size of buffer to send
     * @return Result of operation
     */
    Result
    transfer(uint8_t* txBuf, uint8_t* rxBuf, int length)
    {
        return (Result) mraa_spi_transfer_buf(m_spi, txBuf, rxBuf, length);
    }

    /**
     * Transfer data to and from SPI device Receive pointer may be null if
     * return data is not needed.
     *
     * @param txBuf buffer to send
     * @param rxBuf buffer to optionally receive data from spi device
     * @param length size of buffer to send
     * @return Result of operation
     */
    Result
    transfer_word(uint16_t* txBuf, uint16_t* rxBuf, int length)
    {
        return (Result) mraa_spi_transfer_buf_word(m_spi, txBuf, rxBuf, length);
    }
#endif

    /**
     * Change the SPI lsb mode
     *
     * @param lsb Use least significant bit transmission - 0 for msbi
     * @return Result of operation
     */
    Result
    lsbmode(bool lsb)
    {
        return (Result) mraa_spi_lsbmode(m_spi, (mraa_boolean_t) lsb);
    }

    /**
     * Set bits per mode on transaction, default is 8
     *
     * @param bits bits per word
     * @return Result of operation
     */
    Result
    bitPerWord(unsigned int bits)
    {
        return (Result) mraa_spi_bit_per_word(m_spi, bits);
    }

  private:
    mraa_spi_context m_spi;
};
}
<commit_msg>Spi: Constructor with chip select added in cpp header<commit_after>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#pragma once

#include "spi.h"
#include "types.hpp"
#include <stdexcept>

namespace mraa
{

/**
 * MRAA SPI Modes
 */
typedef enum {
    SPI_MODE0 = 0, /**< CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge,
                      output data (change) on falling edge */
    SPI_MODE1 = 1, /**< CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge,
                      output data (change) on rising edge */
    SPI_MODE2 = 2, /**< CPOL = 1, CPHA = 0, Clock idle low, data is clocked in on falling edge,
                      output data (change) on rising edge */
    SPI_MODE3 = 3, /**< CPOL = 1, CPHA = 1, Clock idle low, data is clocked in on rising, edge
                      output data (change) on falling edge */
} Spi_Mode;

/**
* @brief API to Serial Peripheral Interface
*
* This file defines the SPI interface for libmraa
*
* @snippet Spi-pot.cpp Interesting
*/
class Spi
{
  public:
    /**
     * Initialise SPI object using the board mapping to set muxes
     *
     * @param bus to use, as listed in the platform definition, normally 0
     */
    Spi(int bus)
    {
        m_spi = mraa_spi_init(bus);

        if (m_spi == NULL) {
            throw std::invalid_argument("Error initialising SPI bus");
        }
    }

    Spi(int bus, int cs)
    {
        m_spi = mraa_spi_init_raw(bus, cs);

        if (m_spi == NULL) {
            throw std::invalid_argument("Error initialising SPI bus");
        }
    }

    /**
     * Closes spi bus
     */
    ~Spi()
    {
        mraa_spi_stop(m_spi);
    }

    /**
     * Set the SPI device mode. see spidev0-3
     *
     * @param mode the mode. See Linux spidev doc
     * @return Result of operation
     */
    Result
    mode(Spi_Mode mode)
    {
        return (Result) mraa_spi_mode(m_spi, (mraa_spi_mode_t) mode);
    }

    /**
     * Set the SPI device operating clock frequency
     *
     * @param hz the frequency to set in hz
     * @return Result of operation
     */
    Result
    frequency(int hz)
    {
        return (Result) mraa_spi_frequency(m_spi, hz);
    }

    /**
     * Write single byte to the SPI device
     *
     * @param data the byte to send
     * @return data received on the miso line or -1 in case of error
     */
    int
    writeByte(uint8_t data)
    {
        return mraa_spi_write(m_spi, (uint8_t) data);
    }

    /**
     * Write single byte to the SPI device
     *
     * @param data the byte to send
     * @return data received on the miso line
     */
    uint16_t
    write_word(uint16_t data)
    {
        return mraa_spi_write_word(m_spi, (uint16_t) data);
    }

    /**
     * Write buffer of bytes to SPI device The pointer return has to be
     * free'd by the caller. It will return a NULL pointer in cases of
     * error
     *
     * @param txBuf buffer to send
     * @param length size of buffer to send
     * @return uint8_t* data received on the miso line. Same length as passed in
     */
    uint8_t*
    write(uint8_t* txBuf, int length)
    {
        return mraa_spi_write_buf(m_spi, txBuf, length);
    }

#ifndef SWIG
    /**
     * Write buffer of bytes to SPI device The pointer return has to be
     * free'd by the caller. It will return a NULL pointer in cases of
     * error
     *
     * @param txBuf buffer to send
     * @param length size of buffer (in bytes) to send
     * @return uint8_t* data received on the miso line. Same length as passed in
     */
    uint16_t*
    write_word(uint16_t* txBuf, int length)
    {
        return mraa_spi_write_buf_word(m_spi, txBuf, length);
    }
#endif

#ifndef SWIG
    /**
     * Transfer data to and from SPI device Receive pointer may be null if
     * return data is not needed.
     *
     * @param txBuf buffer to send
     * @param rxBuf buffer to optionally receive data from spi device
     * @param length size of buffer to send
     * @return Result of operation
     */
    Result
    transfer(uint8_t* txBuf, uint8_t* rxBuf, int length)
    {
        return (Result) mraa_spi_transfer_buf(m_spi, txBuf, rxBuf, length);
    }

    /**
     * Transfer data to and from SPI device Receive pointer may be null if
     * return data is not needed.
     *
     * @param txBuf buffer to send
     * @param rxBuf buffer to optionally receive data from spi device
     * @param length size of buffer to send
     * @return Result of operation
     */
    Result
    transfer_word(uint16_t* txBuf, uint16_t* rxBuf, int length)
    {
        return (Result) mraa_spi_transfer_buf_word(m_spi, txBuf, rxBuf, length);
    }
#endif

    /**
     * Change the SPI lsb mode
     *
     * @param lsb Use least significant bit transmission - 0 for msbi
     * @return Result of operation
     */
    Result
    lsbmode(bool lsb)
    {
        return (Result) mraa_spi_lsbmode(m_spi, (mraa_boolean_t) lsb);
    }

    /**
     * Set bits per mode on transaction, default is 8
     *
     * @param bits bits per word
     * @return Result of operation
     */
    Result
    bitPerWord(unsigned int bits)
    {
        return (Result) mraa_spi_bit_per_word(m_spi, bits);
    }

  private:
    mraa_spi_context m_spi;
};
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdocumentgallery.h"

#include "qabstractgallery_p.h"

#include "qgallerycontainerrequest.h"
#include "qgallerycopyrequest.h"
#include "qgallerycountrequest.h"
#include "qgalleryfilterrequest.h"
#include "qgalleryitemrequest.h"
#include "qgallerymoverequest.h"
#include "qgalleryremoverequest.h"
#include "qgalleryurlrequest.h"

#include "qgalleryerrorresponse_p.h"
#include "qgallerytrackeraggregatelistresponse_p.h"
#include "qgallerytrackercountresponse_p.h"
#include "qgallerytrackerfilecopyresponse_p.h"
#include "qgallerytrackerfilelistresponse_p.h"
#include "qgallerytrackerfilemoveresponse_p.h"
#include "qgallerytrackerfileremoveresponse_p.h"
#include "qgallerytrackerschema_p.h"
#include "qgallerytrackerurlresponse_p.h"

#include <QtDBus/qdbusmetatype.h>

QTM_BEGIN_NAMESPACE

class QDocumentGalleryPrivate : public QAbstractGalleryPrivate
{
public:
    QGalleryAbstractResponse *createItemResponse(QGalleryItemRequest *request);
    QGalleryAbstractResponse *createUrlResponse(QGalleryUrlRequest *request);
    QGalleryAbstractResponse *createContainerResponse(QGalleryContainerRequest *request);
    QGalleryAbstractResponse *createFilterResponse(QGalleryFilterRequest *request);
    QGalleryAbstractResponse *createCountResponse(QGalleryCountRequest *request);
    QGalleryAbstractResponse *createCopyResponse(QGalleryCopyRequest *request);
    QGalleryAbstractResponse *createMoveResponse(QGalleryMoveRequest *request);
    QGalleryAbstractResponse *createRemoveResponse(QGalleryRemoveRequest *request);

private:
    QGalleryDBusInterfacePointer metaDataInterface();
    QGalleryDBusInterfacePointer searchInterface();
    QGalleryDBusInterfacePointer fileInterface();

    QGalleryDBusInterfacePointer metaDataService;
    QGalleryDBusInterfacePointer searchService;
    QGalleryDBusInterfacePointer fileService;
};

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::metaDataInterface()
{
    if (!metaDataService) {
        metaDataService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Metadata"),
                QLatin1String("org.freedesktop.Tracker.Metadata"));
    }
    return metaDataService;
}

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::searchInterface()
{
    if (!searchService) {
        searchService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Search"),
                QLatin1String("org.freedesktop.Tracker.Search"));
    }
    return searchService;
}

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::fileInterface()
{
    if (!fileService) {
        fileService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Files"),
                QLatin1String("org.freedesktop.Tracker.Files"));
    }
    return fileService;
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createItemResponse(QGalleryItemRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.resolveItemType(request->itemId());

    QString query = schema.buildIdQuery(&result, request->itemId());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        QGalleryAbstractResponse *response = 0;
        if (schema.isFileType()) {
            response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    QStringList(),
                    1);
            response->setCursorPosition(0);
        } else if (schema.isAggregateType()) {
            response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    QStringList(),
                    1);
            response->setCursorPosition(0);
        } else {
            result = QGalleryAbstractRequest::InvalidItemError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createUrlResponse(
        QGalleryUrlRequest *request)
{
    return new QGalleryTrackerUrlResponse(fileInterface(), request->itemUrl(), request->create());
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createContainerResponse(
        QGalleryContainerRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildContainerQuery(&result, request->containerId());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        QGalleryAbstractResponse *response = 0;
        if (schema.isFileType()) {
            response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else if (schema.isAggregateType()) {
            response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else {
            result = QGalleryAbstractRequest::ItemTypeError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createFilterResponse(
        QGalleryFilterRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildFilterQuery(&result, request->containerId(), request->filter());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        if (schema.isFileType()) {
            QGalleryAbstractResponse *response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else if (schema.isAggregateType()) {
            QGalleryAbstractResponse *response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else {
            result = QGalleryAbstractRequest::ItemTypeError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createCountResponse(
        QGalleryCountRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildFilterQuery(&result, request->containerId(), request->filter());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else if (schema.isFileType() || schema.isAggregateType()) {
        return new QGalleryTrackerCountResponse(metaDataInterface(), schema, query);
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createCopyResponse(QGalleryCopyRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        QString destinationPath = schema.uriFromItemId(&result, request->destinationId());

        if (destinationPath.isEmpty()) {
            result = QGalleryAbstractRequest::InvalidDestinationError;
        } else {
            return new QGalleryTrackerFileCopyResponse(
                    metaDataInterface(),
                    schema,
                    request->propertyNames(),
                    fileNames,
                    destinationPath);
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createMoveResponse(QGalleryMoveRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        QString destinationPath = schema.uriFromItemId(&result, request->destinationId());

        if (destinationPath.isEmpty()) {
            result = QGalleryAbstractRequest::InvalidDestinationError;
        } else {
            return new QGalleryTrackerFileMoveResponse(
                    metaDataInterface(),
                    schema,
                    request->propertyNames(),
                    fileNames,
                    destinationPath);
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createRemoveResponse(
        QGalleryRemoveRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        return new QGalleryTrackerFileRemoveResponse(
                metaDataInterface(),
                schema,
                request->propertyNames(),
                fileNames);
    }

    return new QGalleryErrorResponse(result);
}

QDocumentGallery::QDocumentGallery(QObject *parent)
    : QAbstractGallery(*new QDocumentGalleryPrivate, parent)
{
    qDBusRegisterMetaType<QVector<QStringList> >();
}

QDocumentGallery::~QDocumentGallery()
{
}

bool QDocumentGallery::isRequestSupported(QGalleryAbstractRequest::Type type) const
{
    switch (type) {
    case QGalleryAbstractRequest::Item:
    case QGalleryAbstractRequest::Url:
    case QGalleryAbstractRequest::Container:
    case QGalleryAbstractRequest::Filter:
    case QGalleryAbstractRequest::Count:
    case QGalleryAbstractRequest::Copy:
    case QGalleryAbstractRequest::Move:
    case QGalleryAbstractRequest::Remove:
        return true;
    default:
        return false;
    }
}

QStringList QDocumentGallery::itemTypes() const
{
    return QStringList();
}

QGalleryAbstractResponse *QDocumentGallery::createResponse(QGalleryAbstractRequest *request)
{
    Q_D(QDocumentGallery);

    switch (request->type()) {
    case QGalleryAbstractRequest::Item:
        return d->createItemResponse(static_cast<QGalleryItemRequest *>(request));
    case QGalleryAbstractRequest::Url:
        return d->createUrlResponse(static_cast<QGalleryUrlRequest *>(request));
    case QGalleryAbstractRequest::Container:
        return d->createContainerResponse(static_cast<QGalleryContainerRequest *>(request));
    case QGalleryAbstractRequest::Filter:
        return d->createFilterResponse(static_cast<QGalleryFilterRequest *>(request));
    case QGalleryAbstractRequest::Count:
        return d->createCountResponse(static_cast<QGalleryCountRequest *>(request));
    case QGalleryAbstractRequest::Copy:
        return d->createCopyResponse(static_cast<QGalleryCopyRequest *>(request));
    case QGalleryAbstractRequest::Move:
        return d->createMoveResponse(static_cast<QGalleryMoveRequest *>(request));
    case QGalleryAbstractRequest::Remove:
        return d->createRemoveResponse(static_cast<QGalleryRemoveRequest *>(request));
    default:
        return 0;
    }
}

#include "moc_qdocumentgallery.cpp"

QTM_END_NAMESPACE

<commit_msg>Fix item response not returning any results.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdocumentgallery.h"

#include "qabstractgallery_p.h"

#include "qgallerycontainerrequest.h"
#include "qgallerycopyrequest.h"
#include "qgallerycountrequest.h"
#include "qgalleryfilterrequest.h"
#include "qgalleryitemrequest.h"
#include "qgallerymoverequest.h"
#include "qgalleryremoverequest.h"
#include "qgalleryurlrequest.h"

#include "qgalleryerrorresponse_p.h"
#include "qgallerytrackeraggregatelistresponse_p.h"
#include "qgallerytrackercountresponse_p.h"
#include "qgallerytrackerfilecopyresponse_p.h"
#include "qgallerytrackerfilelistresponse_p.h"
#include "qgallerytrackerfilemoveresponse_p.h"
#include "qgallerytrackerfileremoveresponse_p.h"
#include "qgallerytrackerschema_p.h"
#include "qgallerytrackerurlresponse_p.h"

#include <QtDBus/qdbusmetatype.h>

QTM_BEGIN_NAMESPACE

class QDocumentGalleryPrivate : public QAbstractGalleryPrivate
{
public:
    QGalleryAbstractResponse *createItemResponse(QGalleryItemRequest *request);
    QGalleryAbstractResponse *createUrlResponse(QGalleryUrlRequest *request);
    QGalleryAbstractResponse *createContainerResponse(QGalleryContainerRequest *request);
    QGalleryAbstractResponse *createFilterResponse(QGalleryFilterRequest *request);
    QGalleryAbstractResponse *createCountResponse(QGalleryCountRequest *request);
    QGalleryAbstractResponse *createCopyResponse(QGalleryCopyRequest *request);
    QGalleryAbstractResponse *createMoveResponse(QGalleryMoveRequest *request);
    QGalleryAbstractResponse *createRemoveResponse(QGalleryRemoveRequest *request);

private:
    QGalleryDBusInterfacePointer metaDataInterface();
    QGalleryDBusInterfacePointer searchInterface();
    QGalleryDBusInterfacePointer fileInterface();

    QGalleryDBusInterfacePointer metaDataService;
    QGalleryDBusInterfacePointer searchService;
    QGalleryDBusInterfacePointer fileService;
};

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::metaDataInterface()
{
    if (!metaDataService) {
        metaDataService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Metadata"),
                QLatin1String("org.freedesktop.Tracker.Metadata"));
    }
    return metaDataService;
}

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::searchInterface()
{
    if (!searchService) {
        searchService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Search"),
                QLatin1String("org.freedesktop.Tracker.Search"));
    }
    return searchService;
}

QGalleryDBusInterfacePointer QDocumentGalleryPrivate::fileInterface()
{
    if (!fileService) {
        fileService = new QGalleryDBusInterface(
                QLatin1String("org.freedesktop.Tracker"),
                QLatin1String("/org/freedesktop/Tracker/Files"),
                QLatin1String("org.freedesktop.Tracker.Files"));
    }
    return fileService;
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createItemResponse(QGalleryItemRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.resolveItemType(request->itemId());

    QString query = schema.buildIdQuery(&result, request->itemId());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        QGalleryAbstractResponse *response = 0;
        if (schema.isFileType()) {
            response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    QStringList(),
                    1);
            response->setCursorPosition(0);

            return response;
        } else if (schema.isAggregateType()) {
            response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    QStringList(),
                    1);
            response->setCursorPosition(0);

            return response;
        } else {
            result = QGalleryAbstractRequest::InvalidItemError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createUrlResponse(
        QGalleryUrlRequest *request)
{
    return new QGalleryTrackerUrlResponse(fileInterface(), request->itemUrl(), request->create());
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createContainerResponse(
        QGalleryContainerRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildContainerQuery(&result, request->containerId());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        QGalleryAbstractResponse *response = 0;
        if (schema.isFileType()) {
            response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else if (schema.isAggregateType()) {
            response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else {
            result = QGalleryAbstractRequest::ItemTypeError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createFilterResponse(
        QGalleryFilterRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildFilterQuery(&result, request->containerId(), request->filter());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else {
        if (schema.isFileType()) {
            QGalleryAbstractResponse *response = new QGalleryTrackerFileListResponse(
                    searchInterface(),
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else if (schema.isAggregateType()) {
            QGalleryAbstractResponse *response = new QGalleryTrackerAggregateListResponse(
                    metaDataInterface(),
                    schema,
                    query,
                    request->propertyNames(),
                    request->sortPropertyNames(),
                    request->minimumPagedItems());
            response->setCursorPosition(request->initialCursorPosition());

            return response;
        } else {
            result = QGalleryAbstractRequest::ItemTypeError;
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createCountResponse(
        QGalleryCountRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(request->itemType());

    QString query = schema.buildFilterQuery(&result, request->containerId(), request->filter());

    if (result != QGalleryAbstractRequest::Succeeded) {
        qWarning("Invalid Query %d, %s", result, qPrintable(query));
    } else if (schema.isFileType() || schema.isAggregateType()) {
        return new QGalleryTrackerCountResponse(metaDataInterface(), schema, query);
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createCopyResponse(QGalleryCopyRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        QString destinationPath = schema.uriFromItemId(&result, request->destinationId());

        if (destinationPath.isEmpty()) {
            result = QGalleryAbstractRequest::InvalidDestinationError;
        } else {
            return new QGalleryTrackerFileCopyResponse(
                    metaDataInterface(),
                    schema,
                    request->propertyNames(),
                    fileNames,
                    destinationPath);
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createMoveResponse(QGalleryMoveRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        QString destinationPath = schema.uriFromItemId(&result, request->destinationId());

        if (destinationPath.isEmpty()) {
            result = QGalleryAbstractRequest::InvalidDestinationError;
        } else {
            return new QGalleryTrackerFileMoveResponse(
                    metaDataInterface(),
                    schema,
                    request->propertyNames(),
                    fileNames,
                    destinationPath);
        }
    }

    return new QGalleryErrorResponse(result);
}

QGalleryAbstractResponse *QDocumentGalleryPrivate::createRemoveResponse(
        QGalleryRemoveRequest *request)
{
    int result = QGalleryAbstractRequest::Succeeded;

    QGalleryTrackerSchema schema;
    schema.setItemType(QDocumentGallery::File);

    QStringList fileNames = schema.urisFromItemIds(&result, request->itemIds());

    if (fileNames.isEmpty()) {
        if (result == QGalleryAbstractRequest::Succeeded)
            result = QGalleryAbstractRequest::InvalidItemError;
    } else {
        return new QGalleryTrackerFileRemoveResponse(
                metaDataInterface(),
                schema,
                request->propertyNames(),
                fileNames);
    }

    return new QGalleryErrorResponse(result);
}

QDocumentGallery::QDocumentGallery(QObject *parent)
    : QAbstractGallery(*new QDocumentGalleryPrivate, parent)
{
    qDBusRegisterMetaType<QVector<QStringList> >();
}

QDocumentGallery::~QDocumentGallery()
{
}

bool QDocumentGallery::isRequestSupported(QGalleryAbstractRequest::Type type) const
{
    switch (type) {
    case QGalleryAbstractRequest::Item:
    case QGalleryAbstractRequest::Url:
    case QGalleryAbstractRequest::Container:
    case QGalleryAbstractRequest::Filter:
    case QGalleryAbstractRequest::Count:
    case QGalleryAbstractRequest::Copy:
    case QGalleryAbstractRequest::Move:
    case QGalleryAbstractRequest::Remove:
        return true;
    default:
        return false;
    }
}

QStringList QDocumentGallery::itemTypes() const
{
    return QStringList();
}

QGalleryAbstractResponse *QDocumentGallery::createResponse(QGalleryAbstractRequest *request)
{
    Q_D(QDocumentGallery);

    switch (request->type()) {
    case QGalleryAbstractRequest::Item:
        return d->createItemResponse(static_cast<QGalleryItemRequest *>(request));
    case QGalleryAbstractRequest::Url:
        return d->createUrlResponse(static_cast<QGalleryUrlRequest *>(request));
    case QGalleryAbstractRequest::Container:
        return d->createContainerResponse(static_cast<QGalleryContainerRequest *>(request));
    case QGalleryAbstractRequest::Filter:
        return d->createFilterResponse(static_cast<QGalleryFilterRequest *>(request));
    case QGalleryAbstractRequest::Count:
        return d->createCountResponse(static_cast<QGalleryCountRequest *>(request));
    case QGalleryAbstractRequest::Copy:
        return d->createCopyResponse(static_cast<QGalleryCopyRequest *>(request));
    case QGalleryAbstractRequest::Move:
        return d->createMoveResponse(static_cast<QGalleryMoveRequest *>(request));
    case QGalleryAbstractRequest::Remove:
        return d->createRemoveResponse(static_cast<QGalleryRemoveRequest *>(request));
    default:
        return 0;
    }
}

#include "moc_qdocumentgallery.cpp"

QTM_END_NAMESPACE

<|endoftext|>


<commit_before>//===--- LocalTypeData.cpp - Local type data search -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements routines for finding and caching local type data
//  for a search.
//
//===----------------------------------------------------------------------===//

#include "LocalTypeData.h"
#include "Fulfillment.h"
#include "GenMeta.h"
#include "GenProto.h"
#include "IRGenDebugInfo.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/SIL/SILModule.h"

using namespace swift;
using namespace irgen;

LocalTypeDataKey LocalTypeDataKey::getCachingKey() const {
  return { Type, Kind.getCachingKind() };
}

LocalTypeDataKind LocalTypeDataKind::getCachingKind() const {
  // Most local type data kinds are already canonical.
  if (!isConcreteProtocolConformance()) return *this;

  // Map protocol conformances to their root normal conformance.
  auto conformance = getConcreteProtocolConformance();
  return forConcreteProtocolWitnessTable(
                                     conformance->getRootNormalConformance());
}

LocalTypeDataCache &IRGenFunction::getOrCreateLocalTypeData() {
  // Lazily allocate it.
  if (LocalTypeData) return *LocalTypeData;
  LocalTypeData = new LocalTypeDataCache();
  return *LocalTypeData;
}

void IRGenFunction::destroyLocalTypeData() {
  delete LocalTypeData;
}

unsigned LocalTypeDataCache::CacheEntry::cost() const {
  switch (getKind()) {
  case Kind::Concrete:
    return static_cast<const ConcreteCacheEntry*>(this)->cost();
  case Kind::Abstract:
    return static_cast<const AbstractCacheEntry*>(this)->cost();
  }
  llvm_unreachable("bad cache entry kind");
}

void LocalTypeDataCache::CacheEntry::erase() const {
  switch (getKind()) {
  case Kind::Concrete:
    delete static_cast<const ConcreteCacheEntry*>(this);
    return;
  case Kind::Abstract:
    delete static_cast<const AbstractCacheEntry*>(this);
    return;
  }
  llvm_unreachable("bad cache entry kind");
}

llvm::Value *IRGenFunction::getLocalTypeData(CanType type,
                                             LocalTypeDataKind kind) {
  assert(LocalTypeData);
  return LocalTypeData->get(*this, LocalTypeDataCache::getKey(type, kind));
}

llvm::Value *IRGenFunction::tryGetConcreteLocalTypeData(LocalTypeDataKey key) {
  if (!LocalTypeData) return nullptr;
  return LocalTypeData->tryGet(*this, key, /*allow abstract*/ false);
}

llvm::Value *IRGenFunction::tryGetLocalTypeData(LocalTypeDataKey key) {
  if (!LocalTypeData) return nullptr;
  return LocalTypeData->tryGet(*this, key);
}

llvm::Value *LocalTypeDataCache::tryGet(IRGenFunction &IGF, Key key,
                                        bool allowAbstract) {
  auto it = Map.find(key);
  if (it == Map.end()) return nullptr;
  auto &chain = it->second;

  CacheEntry *best = nullptr;
  Optional<unsigned> bestCost;

  CacheEntry *next = chain.Root, *nextPrev = nullptr;
  while (next) {
    CacheEntry *cur = next, *curPrev = nextPrev;
    nextPrev = cur;
    next = cur->getNext();

    // Ignore abstract entries if so requested.
    if (!allowAbstract && cur->getKind() != CacheEntry::Kind::Concrete)
      continue;

    // Ignore unacceptable entries.
    if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint))
      continue;

    // If there's a collision, compare by cost, ignoring higher-cost entries.
    if (best) {
      // Compute the cost of the best entry if we haven't done so already.
      // If that's zero, go ahead and short-circuit out.
      if (!bestCost) {
        bestCost = best->cost();
        if (*bestCost == 0) break;
      }

      auto curCost = cur->cost();
      if (curCost >= *bestCost) continue;

      // Replace the best cost and fall through.
      bestCost = curCost;
    }
    best = cur;
  }

  // If we didn't find anything, we're done.
  if (!best) return nullptr;

  // Okay, we've found the best entry available.
  switch (best->getKind()) {

  // For concrete caches, this is easy.
  case CacheEntry::Kind::Concrete:
    return static_cast<ConcreteCacheEntry*>(best)->Value;

  // For abstract caches, we need to follow a path.
  case CacheEntry::Kind::Abstract: {
    auto entry = static_cast<AbstractCacheEntry*>(best);

    // Follow the path.
    auto &source = AbstractSources[entry->SourceIndex];
    auto result = entry->follow(IGF, source);

    // Following the path automatically caches at every point along it,
    // including the end.
    assert(chain.Root->DefinitionPoint == IGF.getActiveDominancePoint());
    assert(chain.Root->getKind() == CacheEntry::Kind::Concrete);

    return result;
  }

  }
  llvm_unreachable("bad cache entry kind");
}

llvm::Value *
LocalTypeDataCache::AbstractCacheEntry::follow(IRGenFunction &IGF,
                                               AbstractSource &source) const {
  switch (source.getKind()) {
  case AbstractSource::Kind::TypeMetadata:
    return Path.followFromTypeMetadata(IGF, source.getType(),
                                       source.getValue(), nullptr);

  case AbstractSource::Kind::ProtocolWitnessTable:
    return Path.followFromWitnessTable(IGF, source.getType(),
                                       source.getProtocolConformance(),
                                       source.getValue(), nullptr);
  }
  llvm_unreachable("bad source kind");
}

static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
                                               LocalTypeDataKey key,
                                               llvm::Value *data) {
  // Only if debug info is enabled.
  if (!IGF.IGM.DebugInfo) return;

  // Only for type metadata.
  if (key.Kind != LocalTypeDataKind::forTypeMetadata()) return;

  // Only for archetypes, and not for opened archetypes.
  auto type = dyn_cast<ArchetypeType>(key.Type);
  if (!type) return;
  if (type->getOpenedExistentialType()) return;

  // At -O0, create an alloca to keep the type alive.
  auto name = type->getFullName();
  if (!IGF.IGM.IRGen.Opts.Optimize) {
    auto temp = IGF.createAlloca(data->getType(), IGF.IGM.getPointerAlignment(),
                                 name);
    IGF.Builder.CreateStore(data, temp);
    data = temp.getAddress();
  }

  // Emit debug info for the metadata.
  IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data, name);
}

void IRGenFunction::setScopedLocalTypeData(LocalTypeDataKey key,
                                           llvm::Value *data) {
  maybeEmitDebugInfoForLocalTypeData(*this, key, data);

  // Register with the active ConditionalDominanceScope if necessary.
  bool isConditional = isConditionalDominancePoint();
  if (isConditional) {
    registerConditionalLocalTypeDataKey(key);
  }

  getOrCreateLocalTypeData().addConcrete(getActiveDominancePoint(),
                                         isConditional, key, data);
}

void IRGenFunction::setUnscopedLocalTypeData(LocalTypeDataKey key,
                                             llvm::Value *data) {
  maybeEmitDebugInfoForLocalTypeData(*this, key, data);

  // This is supportable, but it would require ensuring that we add the
  // entry after any conditional entries; otherwise the stack discipline
  // will get messed up.
  assert(!isConditionalDominancePoint() &&
         "adding unscoped local type data while in conditional scope");
  getOrCreateLocalTypeData().addConcrete(DominancePoint::universal(),
                                         /*conditional*/ false, key, data);
}

void IRGenFunction::bindLocalTypeDataFromTypeMetadata(CanType type,
                                                      IsExact_t isExact,
                                                      llvm::Value *metadata) {
  // Remember that we have this type metadata concretely.
  if (isExact) {
    if (!metadata->hasName()) setTypeMetadataName(IGM, metadata, type);
    setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), metadata);
  }

  // Don't bother adding abstract fulfillments at a conditional dominance
  // point; we're too likely to throw them all away.
  if (isConditionalDominancePoint())
    return;

  getOrCreateLocalTypeData()
    .addAbstractForTypeMetadata(*this, type, isExact, metadata);
}

void LocalTypeDataCache::addAbstractForTypeMetadata(IRGenFunction &IGF,
                                                    CanType type,
                                                    IsExact_t isExact,
                                                    llvm::Value *metadata) {
  // Look for anything at all that's fulfilled by this.  If we don't find
  // anything, stop.
  FulfillmentMap fulfillments;
  if (!fulfillments.searchTypeMetadata(IGF.IGM, type, isExact,
                                       /*source*/ 0, MetadataPath(),
                                       FulfillmentMap::Everything())) {
    return;
  }

  addAbstractForFulfillments(IGF, std::move(fulfillments),
                             [&]() -> AbstractSource {
    return AbstractSource(type, metadata);
  });
}

void LocalTypeDataCache::
addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments,
                           llvm::function_ref<AbstractSource()> createSource) {
  // Add the source lazily.
  Optional<unsigned> sourceIndex;
  auto getSourceIndex = [&]() -> unsigned {
    if (!sourceIndex) {
      AbstractSources.emplace_back(createSource());
      sourceIndex = AbstractSources.size() - 1;
    }
    return *sourceIndex;
  };

  for (auto &fulfillment : fulfillments) {
    CanType type = CanType(fulfillment.first.first);
    LocalTypeDataKind localDataKind;

    // For now, ignore witness-table fulfillments when they're not for
    // archetypes.
    if (ProtocolDecl *protocol = fulfillment.first.second) {
      if (auto archetype = dyn_cast<ArchetypeType>(type)) {
        auto conformsTo = archetype->getConformsTo();
        auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol);
        if (it == conformsTo.end()) continue;
        localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it);
      } else {
        continue;
      }

    } else {
      // Ignore type metadata fulfillments for non-dependent types that
      // we can produce very cheaply.  We don't want to end up emitting
      // the type metadata for Int by chasing through N layers of metadata
      // just because that path happens to be in the cache.
      if (!type->hasArchetype() &&
          isTypeMetadataAccessTrivial(IGF.IGM, type)) {
        continue;
      }

      localDataKind = LocalTypeDataKind::forTypeMetadata();
    }

    // Find the chain for the key.
    auto key = getKey(type, localDataKind);
    auto &chain = Map[key];

    // Check whether there's already an entry that's at least as good as the
    // fulfillment.
    Optional<unsigned> fulfillmentCost;
    auto getFulfillmentCost = [&]() -> unsigned {
      if (!fulfillmentCost)
        fulfillmentCost = fulfillment.second.Path.cost();
      return *fulfillmentCost;
    };

    bool isConditional = IGF.isConditionalDominancePoint();

    bool foundBetter = false;
    for (CacheEntry *cur = chain.Root, *last = nullptr; cur;
         last = cur, cur = cur->getNext()) {
      // Ensure the entry is acceptable.
      if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint))
        continue;

      // Ensure that the entry isn't better than the fulfillment.
      auto curCost = cur->cost();
      if (curCost == 0 || curCost <= getFulfillmentCost()) {
        foundBetter = true;
        break;
      }

      // If the entry is defined at the current point, (1) we know there
      // won't be a better entry and (2) we should remove it.
      if (cur->DefinitionPoint == IGF.getActiveDominancePoint() &&
          !isConditional) {
        // Splice it out of the chain.
        assert(!cur->isConditional());
        chain.eraseEntry(last, cur);
        break;
      }
    }
    if (foundBetter) continue;

    // Okay, make a new entry.

    // Register with the conditional dominance scope if necessary.
    if (isConditional) {
      IGF.registerConditionalLocalTypeDataKey(key);
    }

    // Allocate the new entry.
    auto newEntry = new AbstractCacheEntry(IGF.getActiveDominancePoint(),
                                           isConditional,
                                           getSourceIndex(),
                                           std::move(fulfillment.second.Path));

    // Add it to the front of the chain.
    chain.push_front(newEntry);
  }
}

void LocalTypeDataCache::dump() const {
  auto &out = llvm::errs();

  if (Map.empty()) {
    out << "(empty)\n";
    return;
  }

  for (auto &mapEntry : Map) {
    mapEntry.first.print(out);
    out << " => [";

    if (mapEntry.second.Root) out << "\n";
    for (auto cur = mapEntry.second.Root; cur; cur = cur->getNext()) {
      out << "  (";
      if (cur->DefinitionPoint.isUniversal()) out << "universal";
      else out << cur->DefinitionPoint.as<void>();
      out << ") ";

      if (cur->isConditional()) out << "conditional ";

      switch (cur->getKind()) {
      case CacheEntry::Kind::Concrete: {
        auto entry = static_cast<const ConcreteCacheEntry*>(cur);
        out << "concrete: " << entry->Value << "\n  ";
        if (!isa<llvm::Instruction>(entry->Value)) out << "  ";
        entry->Value->dump();
        break;
      }

      case CacheEntry::Kind::Abstract: {
        auto entry = static_cast<const AbstractCacheEntry*>(cur);
        out << "abstract: source=" << entry->SourceIndex << "\n";
        break;
      }
      }
    }
    out << "]\n";
  }
}

void LocalTypeDataKey::dump() const {
  print(llvm::errs());
}

void LocalTypeDataKey::print(llvm::raw_ostream &out) const {
  out << "(" << Type.getPointer()
      << " (" << Type << "), ";
  Kind.print(out);
  out << ")";
}

void LocalTypeDataKind::dump() const {
  print(llvm::errs());
}
void LocalTypeDataKind::print(llvm::raw_ostream &out) const {
  if (isConcreteProtocolConformance()) {
    out << "ConcreteConformance(";
    getConcreteProtocolConformance()->printName(out);
    out << ")";
  } else if (isAbstractProtocolConformance()) {
    out << "AbstractConformance("
        << getAbstractProtocolConformance()->getName()
        << ")";
  } else if (Value == TypeMetadata) {
    out << "TypeMetadata";
  } else if (Value == ValueWitnessTable) {
    out << "ValueWitnessTable";
  } else {
    assert(isSingletonKind());
    ValueWitness witness = ValueWitness(Value - ValueWitnessBase);
    out << getValueWitnessName(witness);
  }
}

IRGenFunction::ConditionalDominanceScope::~ConditionalDominanceScope() {
  IGF.ConditionalDominance = OldScope;

  // Remove any conditional entries from the chains that were added in this
  // scope.
  for (auto &key : RegisteredKeys) {
    IGF.LocalTypeData->eraseConditional(key);
  }
}

void LocalTypeDataCache::eraseConditional(ArrayRef<LocalTypeDataKey> keys) {
  for (auto &key : keys) {
    auto &chain = Map[key];

    // Our ability to simply delete the front of the chain relies on an
    // assumption that (1) conditional additions always go to the front of
    // the chain and (2) we never add something unconditionally while in
    // an unconditional scope.
    assert(chain.Root);
    assert(chain.Root->isConditional());
    chain.eraseEntry(nullptr, chain.Root);
  }
}
<commit_msg>[gardening] Remove written, but never read variable. Found with clang-tidy.<commit_after>//===--- LocalTypeData.cpp - Local type data search -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements routines for finding and caching local type data
//  for a search.
//
//===----------------------------------------------------------------------===//

#include "LocalTypeData.h"
#include "Fulfillment.h"
#include "GenMeta.h"
#include "GenProto.h"
#include "IRGenDebugInfo.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/SIL/SILModule.h"

using namespace swift;
using namespace irgen;

LocalTypeDataKey LocalTypeDataKey::getCachingKey() const {
  return { Type, Kind.getCachingKind() };
}

LocalTypeDataKind LocalTypeDataKind::getCachingKind() const {
  // Most local type data kinds are already canonical.
  if (!isConcreteProtocolConformance()) return *this;

  // Map protocol conformances to their root normal conformance.
  auto conformance = getConcreteProtocolConformance();
  return forConcreteProtocolWitnessTable(
                                     conformance->getRootNormalConformance());
}

LocalTypeDataCache &IRGenFunction::getOrCreateLocalTypeData() {
  // Lazily allocate it.
  if (LocalTypeData) return *LocalTypeData;
  LocalTypeData = new LocalTypeDataCache();
  return *LocalTypeData;
}

void IRGenFunction::destroyLocalTypeData() {
  delete LocalTypeData;
}

unsigned LocalTypeDataCache::CacheEntry::cost() const {
  switch (getKind()) {
  case Kind::Concrete:
    return static_cast<const ConcreteCacheEntry*>(this)->cost();
  case Kind::Abstract:
    return static_cast<const AbstractCacheEntry*>(this)->cost();
  }
  llvm_unreachable("bad cache entry kind");
}

void LocalTypeDataCache::CacheEntry::erase() const {
  switch (getKind()) {
  case Kind::Concrete:
    delete static_cast<const ConcreteCacheEntry*>(this);
    return;
  case Kind::Abstract:
    delete static_cast<const AbstractCacheEntry*>(this);
    return;
  }
  llvm_unreachable("bad cache entry kind");
}

llvm::Value *IRGenFunction::getLocalTypeData(CanType type,
                                             LocalTypeDataKind kind) {
  assert(LocalTypeData);
  return LocalTypeData->get(*this, LocalTypeDataCache::getKey(type, kind));
}

llvm::Value *IRGenFunction::tryGetConcreteLocalTypeData(LocalTypeDataKey key) {
  if (!LocalTypeData) return nullptr;
  return LocalTypeData->tryGet(*this, key, /*allow abstract*/ false);
}

llvm::Value *IRGenFunction::tryGetLocalTypeData(LocalTypeDataKey key) {
  if (!LocalTypeData) return nullptr;
  return LocalTypeData->tryGet(*this, key);
}

llvm::Value *LocalTypeDataCache::tryGet(IRGenFunction &IGF, Key key,
                                        bool allowAbstract) {
  auto it = Map.find(key);
  if (it == Map.end()) return nullptr;
  auto &chain = it->second;

  CacheEntry *best = nullptr;
  Optional<unsigned> bestCost;

  CacheEntry *next = chain.Root, *nextPrev = nullptr;
  while (next) {
    CacheEntry *cur = next;
    nextPrev = cur;
    next = cur->getNext();

    // Ignore abstract entries if so requested.
    if (!allowAbstract && cur->getKind() != CacheEntry::Kind::Concrete)
      continue;

    // Ignore unacceptable entries.
    if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint))
      continue;

    // If there's a collision, compare by cost, ignoring higher-cost entries.
    if (best) {
      // Compute the cost of the best entry if we haven't done so already.
      // If that's zero, go ahead and short-circuit out.
      if (!bestCost) {
        bestCost = best->cost();
        if (*bestCost == 0) break;
      }

      auto curCost = cur->cost();
      if (curCost >= *bestCost) continue;

      // Replace the best cost and fall through.
      bestCost = curCost;
    }
    best = cur;
  }

  // If we didn't find anything, we're done.
  if (!best) return nullptr;

  // Okay, we've found the best entry available.
  switch (best->getKind()) {

  // For concrete caches, this is easy.
  case CacheEntry::Kind::Concrete:
    return static_cast<ConcreteCacheEntry*>(best)->Value;

  // For abstract caches, we need to follow a path.
  case CacheEntry::Kind::Abstract: {
    auto entry = static_cast<AbstractCacheEntry*>(best);

    // Follow the path.
    auto &source = AbstractSources[entry->SourceIndex];
    auto result = entry->follow(IGF, source);

    // Following the path automatically caches at every point along it,
    // including the end.
    assert(chain.Root->DefinitionPoint == IGF.getActiveDominancePoint());
    assert(chain.Root->getKind() == CacheEntry::Kind::Concrete);

    return result;
  }

  }
  llvm_unreachable("bad cache entry kind");
}

llvm::Value *
LocalTypeDataCache::AbstractCacheEntry::follow(IRGenFunction &IGF,
                                               AbstractSource &source) const {
  switch (source.getKind()) {
  case AbstractSource::Kind::TypeMetadata:
    return Path.followFromTypeMetadata(IGF, source.getType(),
                                       source.getValue(), nullptr);

  case AbstractSource::Kind::ProtocolWitnessTable:
    return Path.followFromWitnessTable(IGF, source.getType(),
                                       source.getProtocolConformance(),
                                       source.getValue(), nullptr);
  }
  llvm_unreachable("bad source kind");
}

static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
                                               LocalTypeDataKey key,
                                               llvm::Value *data) {
  // Only if debug info is enabled.
  if (!IGF.IGM.DebugInfo) return;

  // Only for type metadata.
  if (key.Kind != LocalTypeDataKind::forTypeMetadata()) return;

  // Only for archetypes, and not for opened archetypes.
  auto type = dyn_cast<ArchetypeType>(key.Type);
  if (!type) return;
  if (type->getOpenedExistentialType()) return;

  // At -O0, create an alloca to keep the type alive.
  auto name = type->getFullName();
  if (!IGF.IGM.IRGen.Opts.Optimize) {
    auto temp = IGF.createAlloca(data->getType(), IGF.IGM.getPointerAlignment(),
                                 name);
    IGF.Builder.CreateStore(data, temp);
    data = temp.getAddress();
  }

  // Emit debug info for the metadata.
  IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data, name);
}

void IRGenFunction::setScopedLocalTypeData(LocalTypeDataKey key,
                                           llvm::Value *data) {
  maybeEmitDebugInfoForLocalTypeData(*this, key, data);

  // Register with the active ConditionalDominanceScope if necessary.
  bool isConditional = isConditionalDominancePoint();
  if (isConditional) {
    registerConditionalLocalTypeDataKey(key);
  }

  getOrCreateLocalTypeData().addConcrete(getActiveDominancePoint(),
                                         isConditional, key, data);
}

void IRGenFunction::setUnscopedLocalTypeData(LocalTypeDataKey key,
                                             llvm::Value *data) {
  maybeEmitDebugInfoForLocalTypeData(*this, key, data);

  // This is supportable, but it would require ensuring that we add the
  // entry after any conditional entries; otherwise the stack discipline
  // will get messed up.
  assert(!isConditionalDominancePoint() &&
         "adding unscoped local type data while in conditional scope");
  getOrCreateLocalTypeData().addConcrete(DominancePoint::universal(),
                                         /*conditional*/ false, key, data);
}

void IRGenFunction::bindLocalTypeDataFromTypeMetadata(CanType type,
                                                      IsExact_t isExact,
                                                      llvm::Value *metadata) {
  // Remember that we have this type metadata concretely.
  if (isExact) {
    if (!metadata->hasName()) setTypeMetadataName(IGM, metadata, type);
    setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), metadata);
  }

  // Don't bother adding abstract fulfillments at a conditional dominance
  // point; we're too likely to throw them all away.
  if (isConditionalDominancePoint())
    return;

  getOrCreateLocalTypeData()
    .addAbstractForTypeMetadata(*this, type, isExact, metadata);
}

void LocalTypeDataCache::addAbstractForTypeMetadata(IRGenFunction &IGF,
                                                    CanType type,
                                                    IsExact_t isExact,
                                                    llvm::Value *metadata) {
  // Look for anything at all that's fulfilled by this.  If we don't find
  // anything, stop.
  FulfillmentMap fulfillments;
  if (!fulfillments.searchTypeMetadata(IGF.IGM, type, isExact,
                                       /*source*/ 0, MetadataPath(),
                                       FulfillmentMap::Everything())) {
    return;
  }

  addAbstractForFulfillments(IGF, std::move(fulfillments),
                             [&]() -> AbstractSource {
    return AbstractSource(type, metadata);
  });
}

void LocalTypeDataCache::
addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments,
                           llvm::function_ref<AbstractSource()> createSource) {
  // Add the source lazily.
  Optional<unsigned> sourceIndex;
  auto getSourceIndex = [&]() -> unsigned {
    if (!sourceIndex) {
      AbstractSources.emplace_back(createSource());
      sourceIndex = AbstractSources.size() - 1;
    }
    return *sourceIndex;
  };

  for (auto &fulfillment : fulfillments) {
    CanType type = CanType(fulfillment.first.first);
    LocalTypeDataKind localDataKind;

    // For now, ignore witness-table fulfillments when they're not for
    // archetypes.
    if (ProtocolDecl *protocol = fulfillment.first.second) {
      if (auto archetype = dyn_cast<ArchetypeType>(type)) {
        auto conformsTo = archetype->getConformsTo();
        auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol);
        if (it == conformsTo.end()) continue;
        localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it);
      } else {
        continue;
      }

    } else {
      // Ignore type metadata fulfillments for non-dependent types that
      // we can produce very cheaply.  We don't want to end up emitting
      // the type metadata for Int by chasing through N layers of metadata
      // just because that path happens to be in the cache.
      if (!type->hasArchetype() &&
          isTypeMetadataAccessTrivial(IGF.IGM, type)) {
        continue;
      }

      localDataKind = LocalTypeDataKind::forTypeMetadata();
    }

    // Find the chain for the key.
    auto key = getKey(type, localDataKind);
    auto &chain = Map[key];

    // Check whether there's already an entry that's at least as good as the
    // fulfillment.
    Optional<unsigned> fulfillmentCost;
    auto getFulfillmentCost = [&]() -> unsigned {
      if (!fulfillmentCost)
        fulfillmentCost = fulfillment.second.Path.cost();
      return *fulfillmentCost;
    };

    bool isConditional = IGF.isConditionalDominancePoint();

    bool foundBetter = false;
    for (CacheEntry *cur = chain.Root, *last = nullptr; cur;
         last = cur, cur = cur->getNext()) {
      // Ensure the entry is acceptable.
      if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint))
        continue;

      // Ensure that the entry isn't better than the fulfillment.
      auto curCost = cur->cost();
      if (curCost == 0 || curCost <= getFulfillmentCost()) {
        foundBetter = true;
        break;
      }

      // If the entry is defined at the current point, (1) we know there
      // won't be a better entry and (2) we should remove it.
      if (cur->DefinitionPoint == IGF.getActiveDominancePoint() &&
          !isConditional) {
        // Splice it out of the chain.
        assert(!cur->isConditional());
        chain.eraseEntry(last, cur);
        break;
      }
    }
    if (foundBetter) continue;

    // Okay, make a new entry.

    // Register with the conditional dominance scope if necessary.
    if (isConditional) {
      IGF.registerConditionalLocalTypeDataKey(key);
    }

    // Allocate the new entry.
    auto newEntry = new AbstractCacheEntry(IGF.getActiveDominancePoint(),
                                           isConditional,
                                           getSourceIndex(),
                                           std::move(fulfillment.second.Path));

    // Add it to the front of the chain.
    chain.push_front(newEntry);
  }
}

void LocalTypeDataCache::dump() const {
  auto &out = llvm::errs();

  if (Map.empty()) {
    out << "(empty)\n";
    return;
  }

  for (auto &mapEntry : Map) {
    mapEntry.first.print(out);
    out << " => [";

    if (mapEntry.second.Root) out << "\n";
    for (auto cur = mapEntry.second.Root; cur; cur = cur->getNext()) {
      out << "  (";
      if (cur->DefinitionPoint.isUniversal()) out << "universal";
      else out << cur->DefinitionPoint.as<void>();
      out << ") ";

      if (cur->isConditional()) out << "conditional ";

      switch (cur->getKind()) {
      case CacheEntry::Kind::Concrete: {
        auto entry = static_cast<const ConcreteCacheEntry*>(cur);
        out << "concrete: " << entry->Value << "\n  ";
        if (!isa<llvm::Instruction>(entry->Value)) out << "  ";
        entry->Value->dump();
        break;
      }

      case CacheEntry::Kind::Abstract: {
        auto entry = static_cast<const AbstractCacheEntry*>(cur);
        out << "abstract: source=" << entry->SourceIndex << "\n";
        break;
      }
      }
    }
    out << "]\n";
  }
}

void LocalTypeDataKey::dump() const {
  print(llvm::errs());
}

void LocalTypeDataKey::print(llvm::raw_ostream &out) const {
  out << "(" << Type.getPointer()
      << " (" << Type << "), ";
  Kind.print(out);
  out << ")";
}

void LocalTypeDataKind::dump() const {
  print(llvm::errs());
}
void LocalTypeDataKind::print(llvm::raw_ostream &out) const {
  if (isConcreteProtocolConformance()) {
    out << "ConcreteConformance(";
    getConcreteProtocolConformance()->printName(out);
    out << ")";
  } else if (isAbstractProtocolConformance()) {
    out << "AbstractConformance("
        << getAbstractProtocolConformance()->getName()
        << ")";
  } else if (Value == TypeMetadata) {
    out << "TypeMetadata";
  } else if (Value == ValueWitnessTable) {
    out << "ValueWitnessTable";
  } else {
    assert(isSingletonKind());
    ValueWitness witness = ValueWitness(Value - ValueWitnessBase);
    out << getValueWitnessName(witness);
  }
}

IRGenFunction::ConditionalDominanceScope::~ConditionalDominanceScope() {
  IGF.ConditionalDominance = OldScope;

  // Remove any conditional entries from the chains that were added in this
  // scope.
  for (auto &key : RegisteredKeys) {
    IGF.LocalTypeData->eraseConditional(key);
  }
}

void LocalTypeDataCache::eraseConditional(ArrayRef<LocalTypeDataKey> keys) {
  for (auto &key : keys) {
    auto &chain = Map[key];

    // Our ability to simply delete the front of the chain relies on an
    // assumption that (1) conditional additions always go to the front of
    // the chain and (2) we never add something unconditionally while in
    // an unconditional scope.
    assert(chain.Root);
    assert(chain.Root->isConditional());
    chain.eraseEntry(nullptr, chain.Root);
  }
}
<|endoftext|>


<commit_before>//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the HTMLRewriter clas, which is used to translate the
//  text of a source file into prettified HTML.
//
//===----------------------------------------------------------------------===//

#include "clang/Rewrite/Rewriter.h"
#include "clang/Rewrite/HTMLRewrite.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MemoryBuffer.h"
#include <sstream>
using namespace clang;

void html::EscapeText(Rewriter& R, unsigned FileID,
                      bool EscapeSpaces, bool ReplaceTabs) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* C = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();

  assert (C <= FileEnd);

  RewriteBuffer &RB = R.getEditBuffer(FileID);

  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {

    switch (*C) {
    default: break;

    case ' ':
      if (EscapeSpaces)
        RB.ReplaceText(FilePos, 1, " ", 6);
      break;

    case '\t':
      if (!ReplaceTabs)
        break;
      if (EscapeSpaces)
        RB.ReplaceText(FilePos, 1, "    ", 6*4);
      else
        RB.ReplaceText(FilePos, 1, "    ", 4);
      break;

    case '<':
      RB.ReplaceText(FilePos, 1, "<", 4);
      break;

    case '>':
      RB.ReplaceText(FilePos, 1, ">", 4);
      break;

    case '&':
      RB.ReplaceText(FilePos, 1, "&", 5);
      break;
    }
  }
}

std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
                             bool ReplaceTabs) {

  unsigned len = s.size();
  std::ostringstream os;

  for (unsigned i = 0 ; i < len; ++i) {

    char c = s[i];
    switch (c) {
    default:
      os << c; break;

    case ' ':
      if (EscapeSpaces) os << " ";
      else os << ' ';
      break;

      case '\t':
        if (ReplaceTabs)
          for (unsigned i = 0; i < 4; ++i)
            os << " ";
        else
          os << c;

        break;

      case '<': os << "<"; break;
      case '>': os << ">"; break;
      case '&': os << "&"; break;
    }
  }

  return os.str();
}

static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
                          unsigned B, unsigned E) {
  llvm::SmallString<100> Str;
  Str += "
";
  Str.append_uint(LineNo);
  Str += "	";

  if (B == E) { // Handle empty lines.
    Str += "
";
    RB.InsertTextBefore(B, &Str[0], Str.size());
  } else {
    RB.InsertTextBefore(B, &Str[0], Str.size());
    RB.InsertTextBefore(E, "
", strlen("
"));
  }
}

void html::AddLineNumbers(Rewriter& R, unsigned FileID) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* FileBeg = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();
  const char* C = FileBeg;
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  assert (C <= FileEnd);

  unsigned LineNo = 0;
  unsigned FilePos = 0;

  while (C != FileEnd) {

    ++LineNo;
    unsigned LineStartPos = FilePos;
    unsigned LineEndPos = FileEnd - FileBeg;

    assert (FilePos <= LineEndPos);
    assert (C < FileEnd);

    // Scan until the newline (or end-of-file).

    while (C != FileEnd) {
      char c = *C;
      ++C;

      if (c == '\n') {
        LineEndPos = FilePos++;
        break;
      }

      ++FilePos;
    }

    AddLineNumber(RB, LineNo, LineStartPos, LineEndPos);
  }

  // Add one big table tag that surrounds all of the code.
  RB.InsertTextBefore(0, "
\n",
                      strlen("
\n"));

  RB.InsertTextAfter(FileEnd - FileBeg, "
", strlen("
"));
}

void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* FileStart = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();

  SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
  SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);

  // Generate header
  R.InsertCStrBefore(StartLoc,
      "\n\n"
      "\n\n");

  // Generate footer

  R.InsertCStrAfter(EndLoc, "\n");
}

/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
/// information about keywords, macro expansions etc.  This uses the macro
/// table state from the end of the file, so it won't be perfectly perfect,
/// but it will be reasonably close.
void html::SyntaxHighlight(Rewriter &R, unsigned FileID, Preprocessor &PP) {
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  // Inform the preprocessor that we want to retain comments as tokens, so we
  // can highlight them.
  PP.SetCommentRetentionState(true, false);

  // Start parsing the specified input file.
  PP.EnterMainSourceFile();

  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
  // macros.
  const SourceManager &SourceMgr = PP.getSourceManager();
  Token Tok;
  PP.LexUnexpandedToken(Tok);

  // Skip tokens from the predefine buffer or whatever else.
  // Consume all of the tokens that come from the predefines buffer.  Those
  // should not be emitted into the output and are guaranteed to be at the
  // start.
  while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
         SourceMgr.getCanonicalFileID(Tok.getLocation()) != FileID)
    PP.LexUnexpandedToken(Tok);

  while (Tok.isNot(tok::eof)) {
    // Since we are lexing unexpanded tokens, all tokens are from the main
    // FileID.
    unsigned TokOffs = SourceMgr.getFullFilePos(Tok.getLocation());
    unsigned TokLen = Tok.getLength();
    switch (Tok.getKind()) {
    default:
      // If this is a pp-identifier, but not a real identifier it must be a
      // keyword.
      if (Tok.getIdentifierInfo() && Tok.isNot(tok::identifier)) {
        RB.InsertTextAfter(TokOffs, "",
                           strlen(""));
        RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));
      }
      break;
    case tok::comment:
      RB.InsertTextAfter(TokOffs, "",
                         strlen(""));
      RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));
      break;
    case tok::hash:
      // FIXME: This isn't working because we're not in raw mode in the lexer.
      // Just cons up our own lexer here?

      // If this is a preprocessor directive, all tokens to end of line are too.
      if (Tok.isAtStartOfLine()) {
        RB.InsertTextAfter(TokOffs, "",
                           strlen(""));
        // Find end of line.  This is a hack.
        const char *LineEnd = SourceMgr.getCharacterData(Tok.getLocation());
        unsigned TokEnd = TokOffs+strcspn(LineEnd, "\n\r");
        RB.InsertTextBefore(TokEnd, "", strlen(""));
      }
      break;
    }

    PP.LexUnexpandedToken(Tok);
  }
  PP.SetCommentRetentionState(false, false);
}

/// HighlightMacros - This uses the macro table state from the end of the
/// file, to reexpand macros and insert (into the HTML) information about the
/// macro expansions.  This won't be perfectly perfect, but it will be
/// reasonably close.
void html::HighlightMacros(Rewriter &R, unsigned FileID, Preprocessor &PP) {
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  // Inform the preprocessor that we don't want comments.
  PP.SetCommentRetentionState(false, false);

  // Start parsing the specified input file.
  PP.EnterMainSourceFile();

  // Lex all the tokens.
  const SourceManager &SourceMgr = PP.getSourceManager();
  Token Tok;
  PP.Lex(Tok);
  while (Tok.isNot(tok::eof)) {
    // Ignore non-macro tokens.
    if (!Tok.getLocation().isMacroID()) {
      PP.Lex(Tok);
      continue;
    }

    // Ignore tokens whose logical location was not the main file.
    SourceLocation LLoc = SourceMgr.getLogicalLoc(Tok.getLocation());
    std::pair<unsigned, unsigned> LLocInfo =
      SourceMgr.getDecomposedFileLoc(LLoc);

    if (LLocInfo.first != FileID) {
      PP.Lex(Tok);
      continue;
    }

    // Okay, we have the first token of a macro expansion: highlight the
    // instantiation.

    // Get the size of current macro call itself.
    // FIXME: This should highlight the args of a function-like
    // macro, using a heuristic.
    unsigned TokLen = Lexer::MeasureTokenLength(LLoc, SourceMgr);

    unsigned TokOffs = LLocInfo.second;
    RB.InsertTextAfter(TokOffs, "",
                       strlen(""));
    RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));

    // Okay, eat this token, getting the next one.
    PP.Lex(Tok);

    // Skip all the rest of the tokens that are part of this macro
    // instantiation.  It would be really nice to pop up a window with all the
    // spelling of the tokens or something.
    while (!Tok.is(tok::eof) &&
           SourceMgr.getLogicalLoc(Tok.getLocation()) == LLoc)
      PP.Lex(Tok);
  }
}

<commit_msg>switch from relexing with the preprocessor to do syntax highlighting to relexing with the Lexer.  This is cheaper and gives us some advantages.  For now we start highlighting preprocessor directives (which need improvement), and disable  comments.  Comments to be restored later.<commit_after>//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the HTMLRewriter clas, which is used to translate the
//  text of a source file into prettified HTML.
//
//===----------------------------------------------------------------------===//

#include "clang/Rewrite/Rewriter.h"
#include "clang/Rewrite/HTMLRewrite.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MemoryBuffer.h"
#include <sstream>
using namespace clang;

void html::EscapeText(Rewriter& R, unsigned FileID,
                      bool EscapeSpaces, bool ReplaceTabs) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* C = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();

  assert (C <= FileEnd);

  RewriteBuffer &RB = R.getEditBuffer(FileID);

  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {

    switch (*C) {
    default: break;

    case ' ':
      if (EscapeSpaces)
        RB.ReplaceText(FilePos, 1, " ", 6);
      break;

    case '\t':
      if (!ReplaceTabs)
        break;
      if (EscapeSpaces)
        RB.ReplaceText(FilePos, 1, "    ", 6*4);
      else
        RB.ReplaceText(FilePos, 1, "    ", 4);
      break;

    case '<':
      RB.ReplaceText(FilePos, 1, "<", 4);
      break;

    case '>':
      RB.ReplaceText(FilePos, 1, ">", 4);
      break;

    case '&':
      RB.ReplaceText(FilePos, 1, "&", 5);
      break;
    }
  }
}

std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
                             bool ReplaceTabs) {

  unsigned len = s.size();
  std::ostringstream os;

  for (unsigned i = 0 ; i < len; ++i) {

    char c = s[i];
    switch (c) {
    default:
      os << c; break;

    case ' ':
      if (EscapeSpaces) os << " ";
      else os << ' ';
      break;

      case '\t':
        if (ReplaceTabs)
          for (unsigned i = 0; i < 4; ++i)
            os << " ";
        else
          os << c;

        break;

      case '<': os << "<"; break;
      case '>': os << ">"; break;
      case '&': os << "&"; break;
    }
  }

  return os.str();
}

static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
                          unsigned B, unsigned E) {
  llvm::SmallString<100> Str;
  Str += "
";
  Str.append_uint(LineNo);
  Str += "	";

  if (B == E) { // Handle empty lines.
    Str += "
";
    RB.InsertTextBefore(B, &Str[0], Str.size());
  } else {
    RB.InsertTextBefore(B, &Str[0], Str.size());
    RB.InsertTextBefore(E, "
", strlen("
"));
  }
}

void html::AddLineNumbers(Rewriter& R, unsigned FileID) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* FileBeg = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();
  const char* C = FileBeg;
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  assert (C <= FileEnd);

  unsigned LineNo = 0;
  unsigned FilePos = 0;

  while (C != FileEnd) {

    ++LineNo;
    unsigned LineStartPos = FilePos;
    unsigned LineEndPos = FileEnd - FileBeg;

    assert (FilePos <= LineEndPos);
    assert (C < FileEnd);

    // Scan until the newline (or end-of-file).

    while (C != FileEnd) {
      char c = *C;
      ++C;

      if (c == '\n') {
        LineEndPos = FilePos++;
        break;
      }

      ++FilePos;
    }

    AddLineNumber(RB, LineNo, LineStartPos, LineEndPos);
  }

  // Add one big table tag that surrounds all of the code.
  RB.InsertTextBefore(0, "
\n",
                      strlen("
\n"));

  RB.InsertTextAfter(FileEnd - FileBeg, "
", strlen("
"));
}

void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {

  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
  const char* FileStart = Buf->getBufferStart();
  const char* FileEnd = Buf->getBufferEnd();

  SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
  SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);

  // Generate header
  R.InsertCStrBefore(StartLoc,
      "\n\n"
      "\n\n");

  // Generate footer

  R.InsertCStrAfter(EndLoc, "\n");
}

/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
/// information about keywords, macro expansions etc.  This uses the macro
/// table state from the end of the file, so it won't be perfectly perfect,
/// but it will be reasonably close.
void html::SyntaxHighlight(Rewriter &R, unsigned FileID, Preprocessor &PP) {
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  const SourceManager &SourceMgr = PP.getSourceManager();
  std::pair<const char*, const char*> File = SourceMgr.getBufferData(FileID);
  const char *BufferStart = File.first;

  Lexer L(SourceLocation::getFileLoc(FileID, 0), PP.getLangOptions(),
          File.first, File.second);

  // Inform the preprocessor that we want to retain comments as tokens, so we
  // can highlight them.
  //PP.SetCommentRetentionState(true, false);

  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
  // macros.
  Token Tok;
  L.LexRawToken(Tok);

  while (Tok.isNot(tok::eof)) {
    // Since we are lexing unexpanded tokens, all tokens are from the main
    // FileID.
    unsigned TokOffs = SourceMgr.getFullFilePos(Tok.getLocation());
    unsigned TokLen = Tok.getLength();
    switch (Tok.getKind()) {
    default: break;
    case tok::identifier: {
      // Fill in Result.IdentifierInfo, looking up the identifier in the
      // identifier table.
      IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs);

      // If this is a pp-identifier, for a keyword, highlight it as such.
      if (II->getTokenID() != tok::identifier) {
        RB.InsertTextAfter(TokOffs, "",
                           strlen(""));
        RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));
      }
      break;
    }
    case tok::comment:
      RB.InsertTextAfter(TokOffs, "",
                         strlen(""));
      RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));
      break;
    case tok::hash:
      // FIXME: This isn't working because we're not in raw mode in the lexer.
      // Just cons up our own lexer here?

      // If this is a preprocessor directive, all tokens to end of line are too.
      if (Tok.isAtStartOfLine()) {
        RB.InsertTextAfter(TokOffs, "",
                           strlen(""));
        // Find end of line.  This is a hack.
        const char *LineEnd = SourceMgr.getCharacterData(Tok.getLocation());
        unsigned TokEnd = TokOffs+strcspn(LineEnd, "\n\r");
        RB.InsertTextBefore(TokEnd, "", strlen(""));
      }
      break;
    }

    L.LexRawToken(Tok);
  }
}

/// HighlightMacros - This uses the macro table state from the end of the
/// file, to reexpand macros and insert (into the HTML) information about the
/// macro expansions.  This won't be perfectly perfect, but it will be
/// reasonably close.
void html::HighlightMacros(Rewriter &R, unsigned FileID, Preprocessor &PP) {
  RewriteBuffer &RB = R.getEditBuffer(FileID);

  // Inform the preprocessor that we don't want comments.
  PP.SetCommentRetentionState(false, false);

  // Start parsing the specified input file.
  PP.EnterMainSourceFile();

  // Lex all the tokens.
  const SourceManager &SourceMgr = PP.getSourceManager();
  Token Tok;
  PP.Lex(Tok);
  while (Tok.isNot(tok::eof)) {
    // Ignore non-macro tokens.
    if (!Tok.getLocation().isMacroID()) {
      PP.Lex(Tok);
      continue;
    }

    // Ignore tokens whose logical location was not the main file.
    SourceLocation LLoc = SourceMgr.getLogicalLoc(Tok.getLocation());
    std::pair<unsigned, unsigned> LLocInfo =
      SourceMgr.getDecomposedFileLoc(LLoc);

    if (LLocInfo.first != FileID) {
      PP.Lex(Tok);
      continue;
    }

    // Okay, we have the first token of a macro expansion: highlight the
    // instantiation.

    // Get the size of current macro call itself.
    // FIXME: This should highlight the args of a function-like
    // macro, using a heuristic.
    unsigned TokLen = Lexer::MeasureTokenLength(LLoc, SourceMgr);

    unsigned TokOffs = LLocInfo.second;
    RB.InsertTextAfter(TokOffs, "",
                       strlen(""));
    RB.InsertTextBefore(TokOffs+TokLen, "", strlen(""));

    // Okay, eat this token, getting the next one.
    PP.Lex(Tok);

    // Skip all the rest of the tokens that are part of this macro
    // instantiation.  It would be really nice to pop up a window with all the
    // spelling of the tokens or something.
    while (!Tok.is(tok::eof) &&
           SourceMgr.getLogicalLoc(Tok.getLocation()) == LLoc)
      PP.Lex(Tok);
  }
}

<|endoftext|>