<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "cmsis_os.h"
#include "fvp_emac.h"
#include "mbed_interface.h"
#include "mbed_assert.h"
#include "netsocket/nsapi_types.h"
#include "mbed_shared_queues.h"

/********************************************************************************
 * Internal data
 ********************************************************************************/

#define THREAD_STACKSIZE          512

/* Flags for worker thread */
#define FLAG_TX  (0x1u << 0)
#define FLAG_RX  (0x1u << 1)

/** \brief Driver thread priority */
#define THREAD_PRIORITY (osPriorityNormal)

#define PHY_TASK_PERIOD_MS      200

fvp_EMAC::fvp_EMAC() : _thread(THREAD_PRIORITY,THREAD_STACKSIZE,NULL,"fvp_emac_thread")

{
}

void fvp_EMAC::ethernet_callback(lan91_event_t event, void *param)
{
    fvp_EMAC *enet = static_cast<fvp_EMAC *>(param);
    switch (event)
    {
      case LAN91_RxEvent:
        enet->rx_isr();
        break;
      case LAN91_TxEvent:
        enet->tx_isr();
        break;
      default:
        break;
    }
}

/** \brief Ethernet receive interrupt handler */
void fvp_EMAC::rx_isr()
{
    _thread.flags_set(FLAG_RX);
}

/** \brief Ethernet transmit interrupt handler */
void fvp_EMAC::tx_isr()
{
    _thread.flags_set(FLAG_TX);
}

/** \brief Low level init of the MAC and PHY. */
bool fvp_EMAC::low_level_init_successful()
{
    LAN91_init();
    LAN91_SetCallback(&fvp_EMAC::ethernet_callback, this);
    return true;
}

/** \brief  Worker thread.
 *
 * Woken by thread flags to receive packets or clean up transmit
 *
 *  \param[in] pvParameters pointer to the interface data
 */
void fvp_EMAC::thread_function(void* pvParameters)
{
    struct fvp_EMAC *fvp_enet = static_cast<fvp_EMAC *>(pvParameters);

    for (;;) {
        uint32_t flags = ThisThread::flags_wait_any(FLAG_RX|FLAG_TX);
        if (flags & FLAG_RX) {
            fvp_enet->packet_rx();
        }
    }
}

/** \brief  Packet reception task
 *
 * This task is called when a packet is received. It will
 * pass the packet to the LWIP core.
 */
void fvp_EMAC::packet_rx()
{
    while(!LAN91_RxFIFOEmpty())
    {
        emac_mem_buf_t *temp_rxbuf = NULL;
        uint32_t *rx_payload_ptr;
        uint32_t rx_length = 0;

        temp_rxbuf = _memory_manager->alloc_heap(FVP_ETH_MAX_FLEN, LAN91_BUFF_ALIGNMENT);

        /* no memory been allocated*/
        if (NULL != temp_rxbuf) {

            rx_payload_ptr = (uint32_t*)_memory_manager->get_ptr(temp_rxbuf);
            rx_length = _memory_manager->get_len(temp_rxbuf);
            bool state;

#ifdef LOCK_RX_THREAD
    /* Get exclusive access */
    _TXLockMutex.lock();
#endif
            state = LAN91_receive_frame(rx_payload_ptr, &rx_length);

#ifdef LOCK_RX_THREAD
    _TXLockMutex.unlock();
#endif
            if(!state)
            {
                _memory_manager->free(temp_rxbuf);
                continue;
            }
            else
            {
                _memory_manager->set_len(temp_rxbuf, rx_length);
            }
            _emac_link_input_cb(temp_rxbuf);
        }
    }
    LAN91_SetInterruptMasks(MSK_RCV);
}

/** \brief  Low level output of a packet. Never call this from an
 *          interrupt context, as it may block until TX descriptors
 *          become available.
 *
 *  \param[in] buf      the MAC packet to send (e.g. IP packet including MAC addresses and type)
 *  \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
 */
bool fvp_EMAC::link_out(emac_mem_buf_t *buf)
{
    // If buffer is chained or not aligned then make a contiguous aligned copy of it
    if (_memory_manager->get_next(buf) ||
        reinterpret_cast<uint32_t>(_memory_manager->get_ptr(buf)) % LAN91_BUFF_ALIGNMENT) {
        emac_mem_buf_t *copy_buf;
        copy_buf = _memory_manager->alloc_heap(_memory_manager->get_total_len(buf), LAN91_BUFF_ALIGNMENT);
        if (NULL == copy_buf) {
            _memory_manager->free(buf);
            return false;
        }

        // Copy to new buffer and free original
        _memory_manager->copy(copy_buf, buf);
        _memory_manager->free(buf);
        buf = copy_buf;
    }

    /* Save the buffer so that it can be freed when transmit is done */
    uint32_t * buffer;
    uint32_t tx_length = 0;
    bool state;
    buffer = (uint32_t *)(_memory_manager->get_ptr(buf));
    tx_length = _memory_manager->get_len(buf);

    /* Get exclusive access */
    _TXLockMutex.lock();

    /* Setup transfers */
    state = LAN91_send_frame(buffer,&tx_length);
    _TXLockMutex.unlock();
    /* Restore access */

    if(!state){
        return false;
    }
    /* Free the buffer */
    _memory_manager->free(buf);

    return true;
}

/** \brief  PHY task monitoring the link */
void fvp_EMAC::phy_task()
{
    // Get current status
    lan91_phy_status_t connection_status;
    connection_status = LAN91_GetLinkStatus();

    if (connection_status != _prev_state && _emac_link_state_cb) {
        _emac_link_state_cb(connection_status);
    }
    _prev_state = connection_status;
}

bool fvp_EMAC::power_up()
{
    /* Initialize the hardware */
    if (!low_level_init_successful()) {
        return false;
    }

    /* Start ethernet Worker thread */
    _thread.start(callback(&fvp_EMAC::thread_function, this));

    /* Trigger thread to deal with any RX packets that arrived before thread was started */
    rx_isr();

    /* PHY monitoring task */
    _prev_state = STATE_LINK_DOWN;

    mbed::mbed_event_queue()->call(mbed::callback(this, &fvp_EMAC::phy_task));

    /* Allow the PHY task to detect the initial link state and set up the proper flags */
    wait_ms(10);

    _phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &fvp_EMAC::phy_task));

    return true;
}

uint32_t fvp_EMAC::get_mtu_size() const
{
    return LAN91_ETH_MTU_SIZE;
}

uint32_t fvp_EMAC::get_align_preference() const
{
    return LAN91_BUFF_ALIGNMENT;
}

void fvp_EMAC::get_ifname(char *name, uint8_t size) const
{
    memcpy(name, FVP_ETH_IF_NAME, (size < sizeof(FVP_ETH_IF_NAME)) ? size : sizeof(FVP_ETH_IF_NAME));
}

uint8_t fvp_EMAC::get_hwaddr_size() const
{
    return FVP_HWADDR_SIZE;
}

bool fvp_EMAC::get_hwaddr(uint8_t *addr) const
{
    read_MACaddr(addr);
    return true;
}

void fvp_EMAC::set_hwaddr(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
{
    _emac_link_input_cb = input_cb;
}

void fvp_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
{
    _emac_link_state_cb = state_cb;
}

void fvp_EMAC::add_multicast_group(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::remove_multicast_group(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::set_all_multicast(bool all)
{
    /* No-op at this stage */
}

void fvp_EMAC::power_down()
{
    /* No-op at this stage */
}

void fvp_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
{
    _memory_manager = &mem_mngr;
}

fvp_EMAC &fvp_EMAC::get_instance() {
    static fvp_EMAC emac;
    return emac;
}

// Weak so a module can override
MBED_WEAK EMAC &EMAC::get_default_instance() {
    return fvp_EMAC::get_instance();
}

/** @} */

/* --------------------------------- End Of File ------------------------------ */
<commit_msg>update wait_ms() to sleep_for()<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "cmsis_os.h"
#include "fvp_emac.h"
#include "mbed_interface.h"
#include "mbed_assert.h"
#include "netsocket/nsapi_types.h"
#include "mbed_shared_queues.h"

/********************************************************************************
 * Internal data
 ********************************************************************************/

#define THREAD_STACKSIZE          512

/* Flags for worker thread */
#define FLAG_TX  (0x1u << 0)
#define FLAG_RX  (0x1u << 1)

/** \brief Driver thread priority */
#define THREAD_PRIORITY (osPriorityNormal)

#define PHY_TASK_PERIOD_MS      200

fvp_EMAC::fvp_EMAC() : _thread(THREAD_PRIORITY,THREAD_STACKSIZE,NULL,"fvp_emac_thread")

{
}

void fvp_EMAC::ethernet_callback(lan91_event_t event, void *param)
{
    fvp_EMAC *enet = static_cast<fvp_EMAC *>(param);
    switch (event)
    {
      case LAN91_RxEvent:
        enet->rx_isr();
        break;
      case LAN91_TxEvent:
        enet->tx_isr();
        break;
      default:
        break;
    }
}

/** \brief Ethernet receive interrupt handler */
void fvp_EMAC::rx_isr()
{
    _thread.flags_set(FLAG_RX);
}

/** \brief Ethernet transmit interrupt handler */
void fvp_EMAC::tx_isr()
{
    _thread.flags_set(FLAG_TX);
}

/** \brief Low level init of the MAC and PHY. */
bool fvp_EMAC::low_level_init_successful()
{
    LAN91_init();
    LAN91_SetCallback(&fvp_EMAC::ethernet_callback, this);
    return true;
}

/** \brief  Worker thread.
 *
 * Woken by thread flags to receive packets or clean up transmit
 *
 *  \param[in] pvParameters pointer to the interface data
 */
void fvp_EMAC::thread_function(void* pvParameters)
{
    struct fvp_EMAC *fvp_enet = static_cast<fvp_EMAC *>(pvParameters);

    for (;;) {
        uint32_t flags = ThisThread::flags_wait_any(FLAG_RX|FLAG_TX);
        if (flags & FLAG_RX) {
            fvp_enet->packet_rx();
        }
    }
}

/** \brief  Packet reception task
 *
 * This task is called when a packet is received. It will
 * pass the packet to the LWIP core.
 */
void fvp_EMAC::packet_rx()
{
    while(!LAN91_RxFIFOEmpty())
    {
        emac_mem_buf_t *temp_rxbuf = NULL;
        uint32_t *rx_payload_ptr;
        uint32_t rx_length = 0;

        temp_rxbuf = _memory_manager->alloc_heap(FVP_ETH_MAX_FLEN, LAN91_BUFF_ALIGNMENT);

        /* no memory been allocated*/
        if (NULL != temp_rxbuf) {

            rx_payload_ptr = (uint32_t*)_memory_manager->get_ptr(temp_rxbuf);
            rx_length = _memory_manager->get_len(temp_rxbuf);
            bool state;

#ifdef LOCK_RX_THREAD
    /* Get exclusive access */
    _TXLockMutex.lock();
#endif
            state = LAN91_receive_frame(rx_payload_ptr, &rx_length);

#ifdef LOCK_RX_THREAD
    _TXLockMutex.unlock();
#endif
            if(!state)
            {
                _memory_manager->free(temp_rxbuf);
                continue;
            }
            else
            {
                _memory_manager->set_len(temp_rxbuf, rx_length);
            }
            _emac_link_input_cb(temp_rxbuf);
        }
    }
    LAN91_SetInterruptMasks(MSK_RCV);
}

/** \brief  Low level output of a packet. Never call this from an
 *          interrupt context, as it may block until TX descriptors
 *          become available.
 *
 *  \param[in] buf      the MAC packet to send (e.g. IP packet including MAC addresses and type)
 *  \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
 */
bool fvp_EMAC::link_out(emac_mem_buf_t *buf)
{
    // If buffer is chained or not aligned then make a contiguous aligned copy of it
    if (_memory_manager->get_next(buf) ||
        reinterpret_cast<uint32_t>(_memory_manager->get_ptr(buf)) % LAN91_BUFF_ALIGNMENT) {
        emac_mem_buf_t *copy_buf;
        copy_buf = _memory_manager->alloc_heap(_memory_manager->get_total_len(buf), LAN91_BUFF_ALIGNMENT);
        if (NULL == copy_buf) {
            _memory_manager->free(buf);
            return false;
        }

        // Copy to new buffer and free original
        _memory_manager->copy(copy_buf, buf);
        _memory_manager->free(buf);
        buf = copy_buf;
    }

    /* Save the buffer so that it can be freed when transmit is done */
    uint32_t * buffer;
    uint32_t tx_length = 0;
    bool state;
    buffer = (uint32_t *)(_memory_manager->get_ptr(buf));
    tx_length = _memory_manager->get_len(buf);

    /* Get exclusive access */
    _TXLockMutex.lock();

    /* Setup transfers */
    state = LAN91_send_frame(buffer,&tx_length);
    _TXLockMutex.unlock();
    /* Restore access */

    if(!state){
        return false;
    }
    /* Free the buffer */
    _memory_manager->free(buf);

    return true;
}

/** \brief  PHY task monitoring the link */
void fvp_EMAC::phy_task()
{
    // Get current status
    lan91_phy_status_t connection_status;
    connection_status = LAN91_GetLinkStatus();

    if (connection_status != _prev_state && _emac_link_state_cb) {
        _emac_link_state_cb(connection_status);
    }
    _prev_state = connection_status;
}

bool fvp_EMAC::power_up()
{
    /* Initialize the hardware */
    if (!low_level_init_successful()) {
        return false;
    }

    /* Start ethernet Worker thread */
    _thread.start(callback(&fvp_EMAC::thread_function, this));

    /* Trigger thread to deal with any RX packets that arrived before thread was started */
    rx_isr();

    /* PHY monitoring task */
    _prev_state = STATE_LINK_DOWN;

    mbed::mbed_event_queue()->call(mbed::callback(this, &fvp_EMAC::phy_task));

    /* Allow the PHY task to detect the initial link state and set up the proper flags */
    ThisThread::sleep_for(10);

    _phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &fvp_EMAC::phy_task));

    return true;
}

uint32_t fvp_EMAC::get_mtu_size() const
{
    return LAN91_ETH_MTU_SIZE;
}

uint32_t fvp_EMAC::get_align_preference() const
{
    return LAN91_BUFF_ALIGNMENT;
}

void fvp_EMAC::get_ifname(char *name, uint8_t size) const
{
    memcpy(name, FVP_ETH_IF_NAME, (size < sizeof(FVP_ETH_IF_NAME)) ? size : sizeof(FVP_ETH_IF_NAME));
}

uint8_t fvp_EMAC::get_hwaddr_size() const
{
    return FVP_HWADDR_SIZE;
}

bool fvp_EMAC::get_hwaddr(uint8_t *addr) const
{
    read_MACaddr(addr);
    return true;
}

void fvp_EMAC::set_hwaddr(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
{
    _emac_link_input_cb = input_cb;
}

void fvp_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
{
    _emac_link_state_cb = state_cb;
}

void fvp_EMAC::add_multicast_group(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::remove_multicast_group(const uint8_t *addr)
{
    /* No-op at this stage */
}

void fvp_EMAC::set_all_multicast(bool all)
{
    /* No-op at this stage */
}

void fvp_EMAC::power_down()
{
    /* No-op at this stage */
}

void fvp_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
{
    _memory_manager = &mem_mngr;
}

fvp_EMAC &fvp_EMAC::get_instance() {
    static fvp_EMAC emac;
    return emac;
}

// Weak so a module can override
MBED_WEAK EMAC &EMAC::get_default_instance() {
    return fvp_EMAC::get_instance();
}

/** @} */

/* --------------------------------- End Of File ------------------------------ */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 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 "CategoryEntriesModel.h"
#include "PropertyContainer.h"
#include <KFileMetaData/UserMetaData>
#include <QDir>
#include <QFileInfo>
#include <QDebug>

class CategoryEntriesModel::Private {
public:
    Private(CategoryEntriesModel* qq)
        : q(qq)
    {};
    ~Private()
    {
        // No deleting the entries - this is done by the master BookListModel already, so do that at your own risk
    }
    CategoryEntriesModel* q;
    QString name;
    QList<BookEntry*> entries;
    QList<CategoryEntriesModel*> categoryModels;

    QObject* wrapBookEntry(const BookEntry* entry) {
        PropertyContainer* obj = new PropertyContainer("book", q);
        obj->setProperty("author", entry->author);
        obj->setProperty("currentPage", QString::number(entry->currentPage));
        obj->setProperty("filename", entry->filename);
        obj->setProperty("filetitle", entry->filetitle);
        obj->setProperty("created", entry->created);
        obj->setProperty("lastOpenedTime", entry->lastOpenedTime);
        obj->setProperty("publisher", entry->publisher);
        obj->setProperty("series", entry->series);
        obj->setProperty("title", entry->title);
        obj->setProperty("totalPages", entry->totalPages);
        obj->setProperty("thumbnail", entry->thumbnail);
        return obj;
    }
};

CategoryEntriesModel::CategoryEntriesModel(QObject* parent)
    : QAbstractListModel(parent)
    , d(new Private(this))
{
    connect(this, SIGNAL(entryDataUpdated(BookEntry*)), this, SLOT(entryDataChanged(BookEntry*)));
    connect(this, SIGNAL(entryRemoved(BookEntry*)), this, SLOT(entryRemove(BookEntry*)));
}

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

QHash<int, QByteArray> CategoryEntriesModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[FilenameRole] = "filename";
    roles[FiletitleRole] = "filetitle";
    roles[TitleRole] = "title";
    roles[SeriesRole] = "series";
    roles[AuthorRole] = "author";
    roles[PublisherRole] = "publisher";
    roles[CreatedRole] = "created";
    roles[LastOpenedTimeRole] = "lastOpenedTime";
    roles[TotalPagesRole] = "totalPages";
    roles[CurrentPageRole] = "currentPage";
    roles[CategoryEntriesModelRole] = "categoryEntriesModel";
    roles[CategoryEntryCountRole] = "categoryEntriesCount";
    roles[ThumbnailRole] = "thumbnail";
    return roles;
}

QVariant CategoryEntriesModel::data(const QModelIndex& index, int role) const
{
    QVariant result;
    if(index.isValid() && index.row() > -1)
    {
        if(index.row() < d->categoryModels.count())
        {
            CategoryEntriesModel* model = d->categoryModels[index.row()];
            switch(role)
            {
                case Qt::DisplayRole:
                case TitleRole:
                    result.setValue(model->name());
                    break;
                case CategoryEntryCountRole:
                    result.setValue(model->bookCount());
                    break;
                case CategoryEntriesModelRole:
                    result.setValue(model);
                    break;
                default:
                    result.setValue(QString("Unknown role"));
                    break;
            }
        }
        else
        {
            const BookEntry* entry = d->entries[index.row() - d->categoryModels.count()];
            switch(role)
            {
                case Qt::DisplayRole:
                case FilenameRole:
                    result.setValue(entry->filename);
                    break;
                case FiletitleRole:
                    result.setValue(entry->filetitle);
                    break;
                case TitleRole:
                    result.setValue(entry->title);
                    break;
                case SeriesRole:
                    result.setValue(entry->series);
                    break;
                case AuthorRole:
                    result.setValue(entry->author);
                    break;
                case PublisherRole:
                    result.setValue(entry->publisher);
                    break;
                case CreatedRole:
                    result.setValue(entry->created);
                    break;
                case LastOpenedTimeRole:
                    result.setValue(entry->lastOpenedTime);
                    break;
                case TotalPagesRole:
                    result.setValue(entry->totalPages);
                    break;
                case CurrentPageRole:
                    result.setValue(entry->currentPage);
                    break;
                case CategoryEntriesModelRole:
                    // Nothing, if we're not equipped with one such...
                    break;
                case CategoryEntryCountRole:
                    result.setValue<int>(0);
                    break;
                case ThumbnailRole:
                    result.setValue(entry->thumbnail);
                    break;
                default:
                    result.setValue(QString("Unknown role"));
                    break;
            }
        }
    }
    return result;
}

int CategoryEntriesModel::rowCount(const QModelIndex& parent) const
{
    if(parent.isValid())
        return 0;
    return d->categoryModels.count() + d->entries.count();
}

void CategoryEntriesModel::append(BookEntry* entry, Roles compareRole)
{
    int insertionIndex = 0;
    for(; insertionIndex < d->entries.count(); ++insertionIndex)
    {
        if(compareRole == CreatedRole)
        {
            if(entry->created <= d->entries.at(insertionIndex)->created)
            { continue; }
            break;
        }
        else
        {
            if(QString::localeAwareCompare(d->entries.at(insertionIndex)->title, entry->title) > 0)
            { break; }
        }
    }
    beginInsertRows(QModelIndex(), insertionIndex, insertionIndex);
    d->entries.insert(insertionIndex, entry);
    endInsertRows();
}

QString CategoryEntriesModel::name() const
{
    return d->name;
}

void CategoryEntriesModel::setName(const QString& newName)
{
    d->name = newName;
}

QObject * CategoryEntriesModel::leafModelForEntry(BookEntry* entry)
{
    QObject* model(0);
    if(d->categoryModels.count() == 0)
    {
        if(d->entries.contains(entry)) {
            model = this;
        }
    }
    else
    {
        Q_FOREACH(CategoryEntriesModel* testModel, d->categoryModels)
        {
            model = testModel->leafModelForEntry(entry);
            if(model) {
                break;
            }
        }
    }
    return model;
}

void CategoryEntriesModel::addCategoryEntry(const QString& categoryName, BookEntry* entry)
{
    if(categoryName.length() > 0)
    {
        QStringList splitName = categoryName.split("/");
//         qDebug() << "Parsing" << categoryName;
        QString nextCategory = splitName.takeFirst();
        CategoryEntriesModel* categoryModel = 0;
        Q_FOREACH(CategoryEntriesModel* existingModel, d->categoryModels)
        {
            if(existingModel->name() == nextCategory)
            {
                categoryModel = existingModel;
                break;
            }
        }
        if(!categoryModel)
        {
            categoryModel = new CategoryEntriesModel(this);
            connect(this, SIGNAL(entryDataUpdated(BookEntry*)), categoryModel, SIGNAL(entryDataUpdated(BookEntry*)));
            connect(this, SIGNAL(entryRemoved(BookEntry*)), categoryModel, SIGNAL(entryRemoved(BookEntry*)));
            categoryModel->setName(nextCategory);

            int insertionIndex = 0;
            for(; insertionIndex < d->categoryModels.count(); ++insertionIndex)
            {
                if(QString::localeAwareCompare(d->categoryModels.at(insertionIndex)->name(), categoryModel->name()) > 0)
                {
                    break;
                }
            }
            beginInsertRows(QModelIndex(), insertionIndex, insertionIndex);
            d->categoryModels.insert(insertionIndex, categoryModel);
            endInsertRows();
        }
        categoryModel->append(entry);
        categoryModel->addCategoryEntry(splitName.join("/"), entry);
    }
}

QObject* CategoryEntriesModel::get(int index)
{
    BookEntry* entry = new BookEntry();
    bool deleteEntry = true;
    if(index > -1 && index < d->entries.count())
    {
        entry = d->entries.at(index);
        deleteEntry = false;
    }
    QObject* obj = d->wrapBookEntry(entry);
    if(deleteEntry)
    {
        delete entry;
    }
    return obj;
}

int CategoryEntriesModel::indexOfFile(QString filename)
{
    int index = -1, i = 0;
    if(QFile::exists(filename))
    {
        Q_FOREACH(BookEntry* entry, d->entries)
        {
            if(entry->filename == filename)
            {
                index = i;
                break;
            }
            ++i;
        }
    }
    return index;
}

bool CategoryEntriesModel::indexIsBook(int index)
{
    if(index < d->categoryModels.count() || index >= rowCount()) {
        return false;
    }
    return true;
}

int CategoryEntriesModel::bookCount() const
{
    return d->entries.count();
}

QObject* CategoryEntriesModel::getEntry(int index)
{
    PropertyContainer* obj = new PropertyContainer("book", this);
    if(index < 0 && index > rowCount() -1) {
        // don't be a silly person, you can't get a nothing...
    }
    else if(index > d->categoryModels.count()) {
        // This is a book - get a book!
        obj = qobject_cast<PropertyContainer*>(get(index - d->categoryModels.count()));
    }
    else {
        CategoryEntriesModel* catEntry = d->categoryModels.at(index);
        obj->setProperty("title", catEntry->name());
        obj->setProperty("categoryEntriesCount", catEntry->rowCount());
        obj->setProperty("entriesModel", QVariant::fromValue(catEntry));
    }
    return obj;
}

QObject* CategoryEntriesModel::bookFromFile(QString filename)
{
    PropertyContainer* obj = qobject_cast<PropertyContainer*>(get(indexOfFile(filename)));
    if(obj->property("filename").toString().isEmpty()) {
        if(QFileInfo::exists(filename)) {
            QFileInfo info(filename);
            obj->setProperty("title", info.completeBaseName());
            obj->setProperty("created", info.created());

            KFileMetaData::UserMetaData data(filename);
            if (data.hasAttribute("peruse.currentPage")) {
                int currentPage = data.attribute("peruse.currentPage").toInt();
                obj->setProperty("currentPage", QVariant::fromValue<int>(currentPage));
            }
            if (data.hasAttribute("peruse.totalPages")) {
                int totalPages = data.attribute("peruse.totalPages").toInt();
                obj->setProperty("totalPages", QVariant::fromValue<int>(totalPages));
            }
            obj->setProperty("filename", filename);

            QString thumbnail;
            if(filename.toLower().endsWith("cbr")) {
                thumbnail = QString("image://comiccover/").append(filename);
            }
#ifdef USE_PERUSE_PDFTHUMBNAILER
            else if(filename.toLower().endsWith("pdf")) {
                thumbnail = QString("image://pdfcover/").append(filename);
            }
#endif
            else {
                thumbnail = QString("image://preview/").append(filename);
            }
            obj->setProperty("thumbnail", thumbnail);
        }
    }
    return obj;
}

void CategoryEntriesModel::entryDataChanged(BookEntry* entry)
{
    int entryIndex = d->entries.indexOf(entry) + d->categoryModels.count();
    QModelIndex changed = index(entryIndex);
    dataChanged(changed, changed);
}

void CategoryEntriesModel::entryRemove(BookEntry* entry)
{
    int listIndex = d->entries.indexOf(entry);
    if(listIndex > -1) {
        int entryIndex = listIndex + d->categoryModels.count();
        beginRemoveRows(QModelIndex(), entryIndex, entryIndex);
        d->entries.removeAll(entry);
        endRemoveRows();
    }
}
<commit_msg>Make the category get function return count as well<commit_after>/*
 * Copyright (C) 2015 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 "CategoryEntriesModel.h"
#include "PropertyContainer.h"
#include <KFileMetaData/UserMetaData>
#include <QDir>
#include <QFileInfo>
#include <QDebug>

class CategoryEntriesModel::Private {
public:
    Private(CategoryEntriesModel* qq)
        : q(qq)
    {};
    ~Private()
    {
        // No deleting the entries - this is done by the master BookListModel already, so do that at your own risk
    }
    CategoryEntriesModel* q;
    QString name;
    QList<BookEntry*> entries;
    QList<CategoryEntriesModel*> categoryModels;

    QObject* wrapBookEntry(const BookEntry* entry) {
        PropertyContainer* obj = new PropertyContainer("book", q);
        obj->setProperty("author", entry->author);
        obj->setProperty("currentPage", QString::number(entry->currentPage));
        obj->setProperty("filename", entry->filename);
        obj->setProperty("filetitle", entry->filetitle);
        obj->setProperty("created", entry->created);
        obj->setProperty("lastOpenedTime", entry->lastOpenedTime);
        obj->setProperty("publisher", entry->publisher);
        obj->setProperty("series", entry->series);
        obj->setProperty("title", entry->title);
        obj->setProperty("totalPages", entry->totalPages);
        obj->setProperty("thumbnail", entry->thumbnail);
        return obj;
    }
};

CategoryEntriesModel::CategoryEntriesModel(QObject* parent)
    : QAbstractListModel(parent)
    , d(new Private(this))
{
    connect(this, SIGNAL(entryDataUpdated(BookEntry*)), this, SLOT(entryDataChanged(BookEntry*)));
    connect(this, SIGNAL(entryRemoved(BookEntry*)), this, SLOT(entryRemove(BookEntry*)));
}

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

QHash<int, QByteArray> CategoryEntriesModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[FilenameRole] = "filename";
    roles[FiletitleRole] = "filetitle";
    roles[TitleRole] = "title";
    roles[SeriesRole] = "series";
    roles[AuthorRole] = "author";
    roles[PublisherRole] = "publisher";
    roles[CreatedRole] = "created";
    roles[LastOpenedTimeRole] = "lastOpenedTime";
    roles[TotalPagesRole] = "totalPages";
    roles[CurrentPageRole] = "currentPage";
    roles[CategoryEntriesModelRole] = "categoryEntriesModel";
    roles[CategoryEntryCountRole] = "categoryEntriesCount";
    roles[ThumbnailRole] = "thumbnail";
    return roles;
}

QVariant CategoryEntriesModel::data(const QModelIndex& index, int role) const
{
    QVariant result;
    if(index.isValid() && index.row() > -1)
    {
        if(index.row() < d->categoryModels.count())
        {
            CategoryEntriesModel* model = d->categoryModels[index.row()];
            switch(role)
            {
                case Qt::DisplayRole:
                case TitleRole:
                    result.setValue(model->name());
                    break;
                case CategoryEntryCountRole:
                    result.setValue(model->bookCount());
                    break;
                case CategoryEntriesModelRole:
                    result.setValue(model);
                    break;
                default:
                    result.setValue(QString("Unknown role"));
                    break;
            }
        }
        else
        {
            const BookEntry* entry = d->entries[index.row() - d->categoryModels.count()];
            switch(role)
            {
                case Qt::DisplayRole:
                case FilenameRole:
                    result.setValue(entry->filename);
                    break;
                case FiletitleRole:
                    result.setValue(entry->filetitle);
                    break;
                case TitleRole:
                    result.setValue(entry->title);
                    break;
                case SeriesRole:
                    result.setValue(entry->series);
                    break;
                case AuthorRole:
                    result.setValue(entry->author);
                    break;
                case PublisherRole:
                    result.setValue(entry->publisher);
                    break;
                case CreatedRole:
                    result.setValue(entry->created);
                    break;
                case LastOpenedTimeRole:
                    result.setValue(entry->lastOpenedTime);
                    break;
                case TotalPagesRole:
                    result.setValue(entry->totalPages);
                    break;
                case CurrentPageRole:
                    result.setValue(entry->currentPage);
                    break;
                case CategoryEntriesModelRole:
                    // Nothing, if we're not equipped with one such...
                    break;
                case CategoryEntryCountRole:
                    result.setValue<int>(0);
                    break;
                case ThumbnailRole:
                    result.setValue(entry->thumbnail);
                    break;
                default:
                    result.setValue(QString("Unknown role"));
                    break;
            }
        }
    }
    return result;
}

int CategoryEntriesModel::rowCount(const QModelIndex& parent) const
{
    if(parent.isValid())
        return 0;
    return d->categoryModels.count() + d->entries.count();
}

void CategoryEntriesModel::append(BookEntry* entry, Roles compareRole)
{
    int insertionIndex = 0;
    for(; insertionIndex < d->entries.count(); ++insertionIndex)
    {
        if(compareRole == CreatedRole)
        {
            if(entry->created <= d->entries.at(insertionIndex)->created)
            { continue; }
            break;
        }
        else
        {
            if(QString::localeAwareCompare(d->entries.at(insertionIndex)->title, entry->title) > 0)
            { break; }
        }
    }
    beginInsertRows(QModelIndex(), insertionIndex, insertionIndex);
    d->entries.insert(insertionIndex, entry);
    endInsertRows();
}

QString CategoryEntriesModel::name() const
{
    return d->name;
}

void CategoryEntriesModel::setName(const QString& newName)
{
    d->name = newName;
}

QObject * CategoryEntriesModel::leafModelForEntry(BookEntry* entry)
{
    QObject* model(0);
    if(d->categoryModels.count() == 0)
    {
        if(d->entries.contains(entry)) {
            model = this;
        }
    }
    else
    {
        Q_FOREACH(CategoryEntriesModel* testModel, d->categoryModels)
        {
            model = testModel->leafModelForEntry(entry);
            if(model) {
                break;
            }
        }
    }
    return model;
}

void CategoryEntriesModel::addCategoryEntry(const QString& categoryName, BookEntry* entry)
{
    if(categoryName.length() > 0)
    {
        QStringList splitName = categoryName.split("/");
//         qDebug() << "Parsing" << categoryName;
        QString nextCategory = splitName.takeFirst();
        CategoryEntriesModel* categoryModel = 0;
        Q_FOREACH(CategoryEntriesModel* existingModel, d->categoryModels)
        {
            if(existingModel->name() == nextCategory)
            {
                categoryModel = existingModel;
                break;
            }
        }
        if(!categoryModel)
        {
            categoryModel = new CategoryEntriesModel(this);
            connect(this, SIGNAL(entryDataUpdated(BookEntry*)), categoryModel, SIGNAL(entryDataUpdated(BookEntry*)));
            connect(this, SIGNAL(entryRemoved(BookEntry*)), categoryModel, SIGNAL(entryRemoved(BookEntry*)));
            categoryModel->setName(nextCategory);

            int insertionIndex = 0;
            for(; insertionIndex < d->categoryModels.count(); ++insertionIndex)
            {
                if(QString::localeAwareCompare(d->categoryModels.at(insertionIndex)->name(), categoryModel->name()) > 0)
                {
                    break;
                }
            }
            beginInsertRows(QModelIndex(), insertionIndex, insertionIndex);
            d->categoryModels.insert(insertionIndex, categoryModel);
            endInsertRows();
        }
        categoryModel->append(entry);
        categoryModel->addCategoryEntry(splitName.join("/"), entry);
    }
}

QObject* CategoryEntriesModel::get(int index)
{
    BookEntry* entry = new BookEntry();
    bool deleteEntry = true;
    if(index > -1 && index < d->entries.count())
    {
        entry = d->entries.at(index);
        deleteEntry = false;
    }
    QObject* obj = d->wrapBookEntry(entry);
    if(deleteEntry)
    {
        delete entry;
    }
    return obj;
}

int CategoryEntriesModel::indexOfFile(QString filename)
{
    int index = -1, i = 0;
    if(QFile::exists(filename))
    {
        Q_FOREACH(BookEntry* entry, d->entries)
        {
            if(entry->filename == filename)
            {
                index = i;
                break;
            }
            ++i;
        }
    }
    return index;
}

bool CategoryEntriesModel::indexIsBook(int index)
{
    if(index < d->categoryModels.count() || index >= rowCount()) {
        return false;
    }
    return true;
}

int CategoryEntriesModel::bookCount() const
{
    return d->entries.count();
}

QObject* CategoryEntriesModel::getEntry(int index)
{
    PropertyContainer* obj = new PropertyContainer("book", this);
    if(index < 0 && index > rowCount() -1) {
        // don't be a silly person, you can't get a nothing...
    }
    else if(index > d->categoryModels.count()) {
        // This is a book - get a book!
        obj = qobject_cast<PropertyContainer*>(get(index - d->categoryModels.count()));
    }
    else {
        CategoryEntriesModel* catEntry = d->categoryModels.at(index);
        obj->setProperty("title", catEntry->name());
        obj->setProperty("categoryEntriesCount", catEntry->bookCount());
        obj->setProperty("entriesModel", QVariant::fromValue(catEntry));
    }
    return obj;
}

QObject* CategoryEntriesModel::bookFromFile(QString filename)
{
    PropertyContainer* obj = qobject_cast<PropertyContainer*>(get(indexOfFile(filename)));
    if(obj->property("filename").toString().isEmpty()) {
        if(QFileInfo::exists(filename)) {
            QFileInfo info(filename);
            obj->setProperty("title", info.completeBaseName());
            obj->setProperty("created", info.created());

            KFileMetaData::UserMetaData data(filename);
            if (data.hasAttribute("peruse.currentPage")) {
                int currentPage = data.attribute("peruse.currentPage").toInt();
                obj->setProperty("currentPage", QVariant::fromValue<int>(currentPage));
            }
            if (data.hasAttribute("peruse.totalPages")) {
                int totalPages = data.attribute("peruse.totalPages").toInt();
                obj->setProperty("totalPages", QVariant::fromValue<int>(totalPages));
            }
            obj->setProperty("filename", filename);

            QString thumbnail;
            if(filename.toLower().endsWith("cbr")) {
                thumbnail = QString("image://comiccover/").append(filename);
            }
#ifdef USE_PERUSE_PDFTHUMBNAILER
            else if(filename.toLower().endsWith("pdf")) {
                thumbnail = QString("image://pdfcover/").append(filename);
            }
#endif
            else {
                thumbnail = QString("image://preview/").append(filename);
            }
            obj->setProperty("thumbnail", thumbnail);
        }
    }
    return obj;
}

void CategoryEntriesModel::entryDataChanged(BookEntry* entry)
{
    int entryIndex = d->entries.indexOf(entry) + d->categoryModels.count();
    QModelIndex changed = index(entryIndex);
    dataChanged(changed, changed);
}

void CategoryEntriesModel::entryRemove(BookEntry* entry)
{
    int listIndex = d->entries.indexOf(entry);
    if(listIndex > -1) {
        int entryIndex = listIndex + d->categoryModels.count();
        beginRemoveRows(QModelIndex(), entryIndex, entryIndex);
        d->entries.removeAll(entry);
        endRemoveRows();
    }
}
<|endoftext|>


<commit_before>#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/Matrix.hh>

#include <iostream>
#include <string>

#include <getopt.h>

using DataType          = float;
using VertexType        = unsigned;
using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;
using Filtration        = aleph::topology::filtrations::Data<Simplex>;

int main( int argc, char** argv )
{
  bool useSuperlevelSets = false;

  {
    static option commandLineOptions[] = {
      { "sublevel"   , no_argument, nullptr, 's' },
      { "superlevel" , no_argument, nullptr, 'S' },
      { nullptr      , 0          , nullptr,  0  }
    };

    int option = -1;
    while( ( option = getopt_long( argc, argv, "sS", commandLineOptions, nullptr ) ) != - 1)
    {
      switch( option )
      {
      case 's':
        useSuperlevelSets = false;
        break;
      case 'S':
        useSuperlevelSets = true;
        break;
      default:
        break;
      }
    }
  }

  if( ( argc - optind ) < 1 )
    return -1;

  std::string filename = argv[1];

  SimplicialComplex K;

  aleph::topology::io::MatrixReader reader;
  reader( filename, K );

  K.sort( Filtration() );

  auto diagrams = aleph::calculatePersistenceDiagrams( K );

  for( auto&& D : diagrams )
  {
    D.removeDiagonal();

    std::cout << D << "\n";
  }
}
<commit_msg>Added superlevel set filtration support<commit_after>#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/Matrix.hh>

#include <functional>
#include <iostream>
#include <string>

#include <getopt.h>

using DataType          = float;
using VertexType        = unsigned;
using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;
using Filtration        = aleph::topology::filtrations::Data<Simplex>;

int main( int argc, char** argv )
{
  bool useSuperlevelSets = false;

  {
    static option commandLineOptions[] = {
      { "sublevel"   , no_argument, nullptr, 's' },
      { "superlevel" , no_argument, nullptr, 'S' },
      { nullptr      , 0          , nullptr,  0  }
    };

    int option = -1;
    while( ( option = getopt_long( argc, argv, "sS", commandLineOptions, nullptr ) ) != - 1)
    {
      switch( option )
      {
      case 's':
        useSuperlevelSets = false;
        break;
      case 'S':
        useSuperlevelSets = true;
        break;
      default:
        break;
      }
    }
  }

  if( ( argc - optind ) < 1 )
    return -1;

  std::string filename = argv[1];

  SimplicialComplex K;

  aleph::topology::io::MatrixReader reader;
  reader( filename, K );

  if( useSuperlevelSets )
  {
    using Filtration =
      aleph::topology::filtrations::Data<Simplex, std::greater<DataType> >;

    K.sort( Filtration() );
  }
  else
    K.sort( Filtration() );

  auto diagrams = aleph::calculatePersistenceDiagrams( K );

  for( auto&& D : diagrams )
  {
    D.removeDiagonal();

    std::cout << D << "\n";
  }
}
<|endoftext|>


<commit_before>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <boost/type_traits.hpp>
#include <boost/tuple/tuple.hpp>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);

            // Read matrix size
            is.clear(); is.str(line);
            precondition(is >> nrows >> ncols, format_error());
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Number of rows.
        size_t rows() const { return nrows; }

        /// Number of rows.
        size_t cols() const { return ncols; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            size_t nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            ptrdiff_t _nnz = _symmetric ? 2 * nnz : nnz;

            if (row_beg != 0 || row_end != n)
                _nnz *= 1.2 * (row_end - row_beg) / n;

            std::vector<Idx> _row; _row.reserve(_nnz);
            std::vector<Idx> _col; _col.reserve(_nnz);
            std::vector<Val> _val; _val.reserve(_nnz);

            ptr.resize(n+1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                i -= 1;
                j -= 1;

                v = read_value<Val>(is);

                if (row_beg <= i && i < row_end) {
                    ++ptr[i - row_beg + 1];

                    _row.push_back(i - row_beg);
                    _col.push_back(j);
                    _val.push_back(v);
                }

                if (_symmetric && i != j && row_beg <= j && j < row_end) {
                    ++ptr[j - row_beg + 1];

                    _row.push_back(j - row_beg);
                    _col.push_back(i);
                    _val.push_back(v);
                }
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0, e = val.size(); k < e; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return boost::make_tuple(row_end - row_beg, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            val.resize((row_end - row_beg) * m);

            for(ptrdiff_t j = 0; j < m; ++j) {
                for(ptrdiff_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    if (row_beg >= i && i < row_end) {
                        is.clear(); is.str(line);
                        val[(i - row_beg) * m + j] = read_value<Val>(is);
                    }
                }
            }

            return boost::make_tuple(row_end - row_beg, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        size_t nrows, ncols;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename boost::enable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename boost::disable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            T x;
            if (boost::is_same<T, char>::value) {
                // Special case:
                // We want to read 8bit integers from MatrixMarket, not chars.
                int i;
                precondition(s >> i, format_error());
                x = static_cast<char>(i);
            } else {
                precondition(s >> x, format_error());
            }
            return x;
        }

};

namespace detail {
template <typename Val>
typename boost::enable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename boost::disable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;
    typedef typename backend::row_iterator<Matrix>::type row_iterator;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(row_iterator a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<commit_msg>Fix a bug in chunked MatrixMarket reader<commit_after>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <boost/type_traits.hpp>
#include <boost/tuple/tuple.hpp>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);

            // Read matrix size
            is.clear(); is.str(line);
            precondition(is >> nrows >> ncols, format_error());
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Number of rows.
        size_t rows() const { return nrows; }

        /// Number of rows.
        size_t cols() const { return ncols; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            size_t nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            ptrdiff_t _nnz = _symmetric ? 2 * nnz : nnz;

            if (row_beg != 0 || row_end != n)
                _nnz *= 1.2 * (row_end - row_beg) / n;

            std::vector<Idx> _row; _row.reserve(_nnz);
            std::vector<Idx> _col; _col.reserve(_nnz);
            std::vector<Val> _val; _val.reserve(_nnz);

            ptr.resize(n+1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                i -= 1;
                j -= 1;

                v = read_value<Val>(is);

                if (row_beg <= i && i < row_end) {
                    ++ptr[i - row_beg + 1];

                    _row.push_back(i - row_beg);
                    _col.push_back(j);
                    _val.push_back(v);
                }

                if (_symmetric && i != j && row_beg <= j && j < row_end) {
                    ++ptr[j - row_beg + 1];

                    _row.push_back(j - row_beg);
                    _col.push_back(i);
                    _val.push_back(v);
                }
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0, e = val.size(); k < e; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return boost::make_tuple(row_end - row_beg, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            val.resize((row_end - row_beg) * m);

            for(ptrdiff_t j = 0; j < m; ++j) {
                for(ptrdiff_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    if (row_beg <= i && i < row_end) {
                        is.clear(); is.str(line);
                        val[(i - row_beg) * m + j] = read_value<Val>(is);
                    }
                }
            }

            return boost::make_tuple(row_end - row_beg, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        size_t nrows, ncols;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename boost::enable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename boost::disable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            T x;
            if (boost::is_same<T, char>::value) {
                // Special case:
                // We want to read 8bit integers from MatrixMarket, not chars.
                int i;
                precondition(s >> i, format_error());
                x = static_cast<char>(i);
            } else {
                precondition(s >> x, format_error());
            }
            return x;
        }

};

namespace detail {
template <typename Val>
typename boost::enable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename boost::disable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;
    typedef typename backend::row_iterator<Matrix>::type row_iterator;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(row_iterator a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>// This file may be redistributed and modified under the terms of the
// GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2000 Stefanus Du Toit

#include "../Stream/Codec.h"

#include "Utility.h"

using namespace std;
using namespace Atlas::Stream;

/** Packed ASCII codec

[type][name]=[data]

{} for message
() for lists
[] for maps
$ for string
@ for int
# for float

*/

class PackedAscii : public Codec
{
public:

    PackedAscii(iostream&, Filter*, Bridge*);

    virtual void Initialise(iostream&, Filter*, Bridge*);

    virtual void MessageBegin();
    virtual void MessageMapBegin();
    virtual void MessageEnd();

    virtual void MapItem(const std::string& name, const Map&);
    virtual void MapItem(const std::string& name, const List&);
    virtual void MapItem(const std::string& name, int);
    virtual void MapItem(const std::string& name, float);
    virtual void MapItem(const std::string& name, const std::string&);
    virtual void MapItem(const std::string& name, const Atlas::Object&);
    virtual void MapEnd();

    virtual void ListItem(const Map&);
    virtual void ListItem(const List&);
    virtual void ListItem(int);
    virtual void ListItem(float);
    virtual void ListItem(const std::string&);
    virtual void ListItem(const Atlas::Object&);
    virtual void ListEnd();

protected:

    iostream& socket;
    Filter* filter;
    Bridge* bridge;
};

namespace {
    Codec::Factory<PackedAscii> factor("PackedAscii", Codec::Metrics(1, 2));
}

PackedAscii::PackedAscii(iostream& socket, Filter* f, Bridge* b) :
    socket(socket), filter(f), bridge(b)
{
}

void PackedAscii::MessageBegin()
{
    socket << "{";
}

void PackedAscii::MessageMapBegin()
{
    socket << "[=";
}

void PackedAscii::MessageEnd()
{
    socket << "}";
}

void PackedAscii::MapItem(const std::string& name, const Map&)
{
    socket << "[" << name << "=";
}

void PackedAscii::MapItem(const std::string& name, const List&)
{
    socket << "(" << name << "=";
}

void PackedAscii::MapItem(const std::string& name, int data)
{
    socket << "@" << name << "=" << data;
}

void PackedAscii::MapItem(const std::string& name, float data)
{
    socket << "#" << name << "=" << data;
}

void PackedAscii::MapItem(const std::string& name, const std::string& data)
{
    socket << "$" << name << "=" << data;
}

void PackedAscii::MapItem(const std::string& name, const Atlas::Object& data)
{
    // FIXME recursive...
}

void PackedAscii::MapEnd()
{
    socket << "]";
}

void PackedAscii::ListItem(const Map&)
{
    socket << "[=";
}

void PackedAscii::ListItem(const List&)
{
    socket << "(=";
}

void PackedAscii::ListItem(int data)
{
    socket << "@=" << data;
}

void PackedAscii::ListItem(float data)
{
    socket << "#=" << data;
}

void PackedAscii::ListItem(const std::string& data)
{
    socket << "$=" << data;
}

void PackedAscii::ListItem(const Atlas::Object& data)
{
    // FIXME recursive...
}

void PackedAscii::ListEnd()
{
    socket << ")";
}
<commit_msg>It actually *uses* hexEncode() now :)<commit_after>// This file may be redistributed and modified under the terms of the
// GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2000 Stefanus Du Toit

#include "../Stream/Codec.h"

#include "Utility.h"

using namespace std;
using namespace Atlas::Stream;

/** Packed ASCII codec

[type][name]=[data]

{} for message
() for lists
[] for maps
$ for string
@ for int
# for float

*/

class PackedAscii : public Codec
{
public:

    PackedAscii(iostream&, Filter*, Bridge*);

    virtual void Initialise(iostream&, Filter*, Bridge*);

    virtual void MessageBegin();
    virtual void MessageMapBegin();
    virtual void MessageEnd();

    virtual void MapItem(const std::string& name, const Map&);
    virtual void MapItem(const std::string& name, const List&);
    virtual void MapItem(const std::string& name, int);
    virtual void MapItem(const std::string& name, float);
    virtual void MapItem(const std::string& name, const std::string&);
    virtual void MapItem(const std::string& name, const Atlas::Object&);
    virtual void MapEnd();

    virtual void ListItem(const Map&);
    virtual void ListItem(const List&);
    virtual void ListItem(int);
    virtual void ListItem(float);
    virtual void ListItem(const std::string&);
    virtual void ListItem(const Atlas::Object&);
    virtual void ListEnd();

protected:

    iostream& socket;
    Filter* filter;
    Bridge* bridge;
};

namespace {
    Codec::Factory<PackedAscii> factor("PackedAscii", Codec::Metrics(1, 2));
}

PackedAscii::PackedAscii(iostream& socket, Filter* f, Bridge* b) :
    socket(socket), filter(f), bridge(b)
{
}

void PackedAscii::MessageBegin()
{
    socket << "{";
}

void PackedAscii::MessageMapBegin()
{
    socket << "[=";
}

void PackedAscii::MessageEnd()
{
    socket << "}";
}

void PackedAscii::MapItem(const std::string& name, const Map&)
{
    socket << "[" << hexEncode("+", "", "+{}[]()@#$=", name) << "=";
}

void PackedAscii::MapItem(const std::string& name, const List&)
{
    socket << "(" << hexEncode("+", "", "+{}[]()@#$=", name) << "=";
}

void PackedAscii::MapItem(const std::string& name, int data)
{
    socket << "@" << hexEncode("+", "", "+{}[]()@#$=", name) << "=" << data;
}

void PackedAscii::MapItem(const std::string& name, float data)
{
    socket << "#" << hexEncode("+", "", "+{}[]()@#$=", name) << "=" << data;
}

void PackedAscii::MapItem(const std::string& name, const std::string& data)
{
    socket << "$" << hexEncode("+", "", "+{}[]()@#$=", name) << "=" <<
            hexEncode("+", "+{}[]()@#$=", "", data);
}

void PackedAscii::MapItem(const std::string& name, const Atlas::Object& data)
{
    // FIXME recursive...
}

void PackedAscii::MapEnd()
{
    socket << "]";
}

void PackedAscii::ListItem(const Map&)
{
    socket << "[=";
}

void PackedAscii::ListItem(const List&)
{
    socket << "(=";
}

void PackedAscii::ListItem(int data)
{
    socket << "@=" << data;
}

void PackedAscii::ListItem(float data)
{
    socket << "#=" << data;
}

void PackedAscii::ListItem(const std::string& data)
{
    socket << "$=" << hexEncode("+", "", "+{}[]()@#$=", data);
}

void PackedAscii::ListItem(const Atlas::Object& data)
{
    // FIXME recursive...
}

void PackedAscii::ListEnd()
{
    socket << ")";
}
<|endoftext|>


<commit_before>#ifndef __ARRAYS_HPP__
#define __ARRAYS_HPP__

#include <string>
#include <type_traits>

#ifdef __CYGWIN__
#include <sstream>
namespace std {
	inline std::string to_string(unsigned long val) { ostringstream os; os << val; return os.str(); }
}
#endif

namespace {
namespace __typedecl {

struct split_string {
	std::string begin;
	std::string end;
	explicit operator std::string() const {
		return begin + end;
	}
};

inline split_string operator+(const std::string& s, const split_string& ss) {
	return { s + ss.begin, ss.end };
}

inline split_string operator+(const split_string& ss, const std::string& s) {
	return { ss.begin, ss.end + s };
}

enum type_type { BASICTYPE, COMPOSITION };
struct basic_type { static constexpr type_type type = BASICTYPE; };
struct composition { static constexpr type_type type = COMPOSITION; };

template <typename T>
struct impl;

template <typename T, type_type = impl<T>::type>
struct prefix_cv_qual_if_basictype;

template <typename T>
struct prefix_cv_qual_if_basictype<T, BASICTYPE> {
	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return impl<T>::value_with_cv_qual(cv_qual, suffix);
	}
};

template <typename T>
struct prefix_cv_qual_if_basictype<T, COMPOSITION> {
	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return impl<T>::value(cv_qual + suffix);
	}
};

template <typename T>
struct impl<const T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const", suffix);
	}
};

template <typename T>
struct impl<volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("volatile", suffix);
	}
};

// Required to disambiguate between <const T> and <volatile T>
template <typename T>
struct impl<const volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const volatile", suffix);
	}
};

template <typename T, bool = std::is_array<T>::value || std::is_function<T>::value>
struct parenthesize_if_array_or_function;

template <typename T>
struct parenthesize_if_array_or_function<T, false> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value(arg);
	}
};

template <typename T>
struct parenthesize_if_array_or_function<T, true> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value("(" + arg + ")");
	}
};

template <typename T>
struct impl<T*> : composition {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("*" + suffix);
	}
};

template <typename T>
struct impl<T&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&" + suffix);
	}
};

template <typename T>
struct impl<T&&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&&" + suffix);
	}
};

template <typename T>
struct array_impl : composition {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + "[]");
	}
};

template <typename T>
struct impl<T[]> : array_impl<T> {};

// Required to disambiguate between <const T> and <T[]>
template <typename T>
struct impl<const T[]> : array_impl<const T> {};

// Required to disambiguate between <volatile T> and <T[]>
template <typename T>
struct impl<volatile T[]> : array_impl<volatile T> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[]>, <const T[]> and <volatile T[]>
template <typename T>
struct impl<const volatile T[]> : array_impl<const volatile T> {};

template <typename T, size_t N>
struct sized_array_impl : composition {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + ("[" + std::to_string(N) + "]"));
	}
};

template <typename T, size_t N>
struct impl<T[N]> : sized_array_impl<T, N> {};

// Required to disambiguate between <const T> and <T[N]>
template <typename T, size_t N>
struct impl<const T[N]> : sized_array_impl<const T, N> {};

// Required to disambiguate between <volatile T> and <T[N]>
template <typename T, size_t N>
struct impl<volatile T[N]> : sized_array_impl<volatile T, N> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[N]>, <const T[N]> and <volatile T[N]>
template <typename T, size_t N>
struct impl<const volatile T[N]> : sized_array_impl<const volatile T, N> {};

template <bool VA, typename... T>
struct type_list_impl;

template <bool VA>
struct type_list_impl<VA> {
	inline static std::string value() {
		return VA ? "..." : "";
	}
};

template <bool VA, typename T>
struct type_list_impl<VA, T> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T>::value()) + (VA ? ", ..." : "");
	}
};

template <bool VA, typename T1, typename T2, typename... U>
struct type_list_impl<VA, T1, T2, U...> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T1>::value()) + ", " + type_list_impl<VA, T2, U...>::value();
	}
};

template <bool P, typename R, bool VA, typename... A>
struct function_impl;

template <typename R, bool VA, typename... A>
struct function_impl<false, R, VA, A...> {
	inline static split_string value(const split_string& infix = {}) {
		return static_cast<std::string>(impl<R>::value()) + infix + "(" + type_list_impl<VA, A...>::value() + ")";
	}
};

template <typename R, bool VA, typename... A>
struct function_impl<true, R, VA, A...> {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<R>::value(prefix + "(" + type_list_impl<VA, A...>::value() + ")");
	}
};

template <typename T>
struct is_pointer_or_reference : std::integral_constant<
	bool,
	std::is_pointer<T>::value || std::is_reference<T>::value
> {};

template <typename R, typename... A>
struct impl<R(A...)>      : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, false, A...> {};

template <typename R, typename... A>
struct impl<R(A..., ...)> : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, true, A...> {};

} /* namespace __typedecl */
} /* unnamed namespace */

template <typename T>
inline std::string typedecl() {
	__typedecl::split_string ss = __typedecl::impl<T>::value();
	return ss.begin + ss.end;
}

template <typename T>
inline std::string namedecl(const std::string& name) {
	__typedecl::split_string ss = __typedecl::impl<T>::value();
	return ss.begin + " " + name + ss.end;
}

#define DEFINE_TYPEDECL(T) \
	namespace { \
	namespace __typedecl { \
	template <> \
	struct impl<T> : basic_type { \
		inline static split_string value(const split_string& suffix = {}) { \
			return #T + suffix; \
		} \
		inline static split_string value_with_cv_qual(const std::string& cv_qual, const split_string& suffix) { \
			return (cv_qual + " " #T) + suffix; \
		} \
	}; \
	} /* namespace __typedecl */ \
	} /* unnamed namespace */

DEFINE_TYPEDECL(void);
DEFINE_TYPEDECL(char);
DEFINE_TYPEDECL(int);

#endif
<commit_msg>Split template specializations where a bool template argument was used<commit_after>#ifndef __ARRAYS_HPP__
#define __ARRAYS_HPP__

#include <string>
#include <type_traits>

#ifdef __CYGWIN__
#include <sstream>
namespace std {
	inline std::string to_string(unsigned long val) { ostringstream os; os << val; return os.str(); }
}
#endif

namespace {
namespace __typedecl {

struct split_string {
	std::string begin;
	std::string end;
	explicit operator std::string() const {
		return begin + end;
	}
};

inline split_string operator+(const std::string& s, const split_string& ss) {
	return { s + ss.begin, ss.end };
}

inline split_string operator+(const split_string& ss, const std::string& s) {
	return { ss.begin, ss.end + s };
}

enum type_type { BASICTYPE, COMPOSITION };
struct basic_type { static constexpr type_type type = BASICTYPE; };
struct composition { static constexpr type_type type = COMPOSITION; };

template <typename T>
struct impl;

template <typename T, type_type = impl<T>::type>
struct prefix_cv_qual_if_basictype;

template <typename T>
struct prefix_cv_qual_if_basictype<T, BASICTYPE> {
	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return impl<T>::value_with_cv_qual(cv_qual, suffix);
	}
};

template <typename T>
struct prefix_cv_qual_if_basictype<T, COMPOSITION> {
	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return impl<T>::value(cv_qual + suffix);
	}
};

template <typename T>
struct impl<const T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const", suffix);
	}
};

template <typename T>
struct impl<volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("volatile", suffix);
	}
};

// Required to disambiguate between <const T> and <volatile T>
template <typename T>
struct impl<const volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const volatile", suffix);
	}
};

template <typename T, bool = std::is_array<T>::value || std::is_function<T>::value>
struct parenthesize_if_array_or_function;

template <typename T>
struct parenthesize_if_array_or_function<T, false> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value(arg);
	}
};

template <typename T>
struct parenthesize_if_array_or_function<T, true> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value("(" + arg + ")");
	}
};

template <typename T>
struct impl<T*> : composition {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("*" + suffix);
	}
};

template <typename T>
struct impl<T&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&" + suffix);
	}
};

template <typename T>
struct impl<T&&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&&" + suffix);
	}
};

template <typename T>
struct array_impl : composition {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + "[]");
	}
};

template <typename T>
struct impl<T[]> : array_impl<T> {};

// Required to disambiguate between <const T> and <T[]>
template <typename T>
struct impl<const T[]> : array_impl<const T> {};

// Required to disambiguate between <volatile T> and <T[]>
template <typename T>
struct impl<volatile T[]> : array_impl<volatile T> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[]>, <const T[]> and <volatile T[]>
template <typename T>
struct impl<const volatile T[]> : array_impl<const volatile T> {};

template <typename T, size_t N>
struct sized_array_impl : composition {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + ("[" + std::to_string(N) + "]"));
	}
};

template <typename T, size_t N>
struct impl<T[N]> : sized_array_impl<T, N> {};

// Required to disambiguate between <const T> and <T[N]>
template <typename T, size_t N>
struct impl<const T[N]> : sized_array_impl<const T, N> {};

// Required to disambiguate between <volatile T> and <T[N]>
template <typename T, size_t N>
struct impl<volatile T[N]> : sized_array_impl<volatile T, N> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[N]>, <const T[N]> and <volatile T[N]>
template <typename T, size_t N>
struct impl<const volatile T[N]> : sized_array_impl<const volatile T, N> {};

template <bool VA, typename... T>
struct type_list_impl;

template <>
struct type_list_impl<true> {
	inline static std::string value() {
		return "...";
	}
};

template <>
struct type_list_impl<false> {
	inline static std::string value() {
		return "";
	}
};

template <typename T>
struct type_list_impl<true, T> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T>::value()) + ", ...";
	}
};

template <typename T>
struct type_list_impl<false, T> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T>::value());
	}
};

template <bool VA, typename T1, typename T2, typename... U>
struct type_list_impl<VA, T1, T2, U...> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T1>::value()) + ", " + type_list_impl<VA, T2, U...>::value();
	}
};

template <bool P, typename R, bool VA, typename... A>
struct function_impl;

template <typename R, bool VA, typename... A>
struct function_impl<false, R, VA, A...> {
	inline static split_string value(const split_string& infix = {}) {
		return static_cast<std::string>(impl<R>::value()) + infix + "(" + type_list_impl<VA, A...>::value() + ")";
	}
};

template <typename R, bool VA, typename... A>
struct function_impl<true, R, VA, A...> {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<R>::value(prefix + "(" + type_list_impl<VA, A...>::value() + ")");
	}
};

template <typename T>
struct is_pointer_or_reference : std::integral_constant<
	bool,
	std::is_pointer<T>::value || std::is_reference<T>::value
> {};

template <typename R, typename... A>
struct impl<R(A...)>      : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, false, A...> {};

template <typename R, typename... A>
struct impl<R(A..., ...)> : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, true, A...> {};

} /* namespace __typedecl */
} /* unnamed namespace */

template <typename T>
inline std::string typedecl() {
	__typedecl::split_string ss = __typedecl::impl<T>::value();
	return ss.begin + ss.end;
}

template <typename T>
inline std::string namedecl(const std::string& name) {
	__typedecl::split_string ss = __typedecl::impl<T>::value();
	return ss.begin + " " + name + ss.end;
}

#define DEFINE_TYPEDECL(T) \
	namespace { \
	namespace __typedecl { \
	template <> \
	struct impl<T> : basic_type { \
		inline static split_string value(const split_string& suffix = {}) { \
			return #T + suffix; \
		} \
		inline static split_string value_with_cv_qual(const std::string& cv_qual, const split_string& suffix) { \
			return (cv_qual + " " #T) + suffix; \
		} \
	}; \
	} /* namespace __typedecl */ \
	} /* unnamed namespace */

DEFINE_TYPEDECL(void);
DEFINE_TYPEDECL(char);
DEFINE_TYPEDECL(int);

#endif
<|endoftext|>