<commit_before>#include "tileManager.h"

#include "data/dataSource.h"
#include "platform.h"
#include "scene/scene.h"
#include "tile/tile.h"
#include "view/view.h"
#include "tileCache.h"

#include "glm/gtx/norm.hpp"

#include <chrono>
#include <algorithm>

#define DBG(...)
//logMsg(__VA_ARGS__)

namespace Tangram {

TileManager::TileManager()
    : m_loadPending(0) {

    // Instantiate workers
    m_workers = std::unique_ptr<TileWorker>(new TileWorker(*this, MAX_WORKERS));

    m_tileCache = std::unique_ptr<TileCache>(new TileCache(DEFAULT_CACHE_SIZE));

    m_dataCallback = [this](std::shared_ptr<TileTask>&& task){
        if (setTileState(*task->tile, TileState::processing)) {
            m_workers->enqueue(std::move(task));
        }
    };
}

TileManager::~TileManager() {
    if (m_workers->isRunning()) {
        m_workers->stop();
    }
    m_tileSets.clear();
}

void TileManager::addDataSource(std::shared_ptr<DataSource>&& dataSource) {
    m_tileSets.push_back({dataSource});
}

void TileManager::tileProcessed(std::shared_ptr<TileTask>&& task) {
    std::lock_guard<std::mutex> lock(m_readyTileMutex);
    m_readyTiles.push_back(std::move(task));
}

bool TileManager::setTileState(Tile& tile, TileState state) {
    std::lock_guard<std::mutex> lock(m_tileStateMutex);

    switch (tile.getState()) {
    case TileState::none:
        if (state == TileState::loading) {
            tile.setState(state);
            m_loadPending++;
            return true;
        }
        if (state == TileState::processing) {
            tile.setState(state);
            return true;
        }
        break;

    case TileState::loading:
        if (state == TileState::processing) {
            tile.setState(state);
            m_loadPending--;
            return true;
        }
        if (state == TileState::canceled) {
            tile.setState(state);
            m_loadPending--;
            return true;
        }
        break;

    case TileState::processing:
        if (state == TileState::ready) {
            tile.setState(state);
            return true;
        }
        break;

    case TileState::canceled:
        // Ignore any state change when tile was canceled
         return false;

    default:
        break;
    }

    if (state == TileState::canceled) {
        tile.setState(state);
        return true;
    }

    logMsg("Wrong state change %d -> %d<<<", tile.getState(), state);
    assert(false);
    return false; // ...
}

void TileManager::clearTileSets() {
    for (auto& tileSet : m_tileSets) {
        for (auto& tile : tileSet.tiles) {
            setTileState(*tile.second, TileState::canceled);
        }
        tileSet.tiles.clear();
    }

    m_tileCache->clear();
    m_loadPending = 0;
}

void TileManager::updateTileSets() {

    m_tileSetChanged = false;
    m_tiles.clear();

    for (auto& tileSet : m_tileSets) {
        updateTileSet(tileSet);
    }

    loadTiles();

    std::sort(m_tiles.begin(), m_tiles.end(), [](auto& a, auto& b){
            return a->getID() < b->getID();
        });

    m_tiles.erase(std::unique(m_tiles.begin(), m_tiles.end()), m_tiles.end());
}

void TileManager::updateTileSet(TileSet& tileSet) {

    auto& tiles = tileSet.tiles;

    std::vector<TileID> removeTiles;

    if (!m_readyTiles.empty()) {
        std::lock_guard<std::mutex> lock(m_readyTileMutex);
        auto it = m_readyTiles.begin();

        while (it != m_readyTiles.end()) {
            auto& task = *it;
            auto& tile = *(task->tile);

            if (tileSet.source.get() == task->source) {

                if (setTileState(tile, TileState::ready)) {
                    clearProxyTiles(tileSet, tile, removeTiles);
                    m_tileSetChanged = true;
                }
                it = m_readyTiles.erase(it);
            } else {
                it++;
            }
        }
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    glm::dvec2 viewCenter(m_view->getPosition().x, -m_view->getPosition().y);

    if (m_view->changedOnLastUpdate() || m_tileSetChanged) {

        // Loop over visibleTiles and add any needed tiles to tileSet
        auto setTilesIter = tiles.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            auto& visTileId = *visTilesIter;
            auto& curTileId = setTilesIter == tiles.end() ? NOT_A_TILE : setTilesIter->first;

            if (visTileId == curTileId) {
                auto& tile = setTilesIter->second;

                if (tile->hasState(TileState::none)) {
                    enqueueLoadTask(tileSet, visTileId, viewCenter);
                } else if (tile->isReady()) {
                    m_tiles.push_back(tile);
                }

                tile->setVisible(true);

                // tiles in both sets match
                ++setTilesIter;
                ++visTilesIter;

            } else if (curTileId == NOT_A_TILE || visTileId < curTileId) {
                // tileSet is missing an element present in visibleTiles
                if (!addTile(tileSet, visTileId)) {
                    enqueueLoadTask(tileSet, visTileId, viewCenter);
                }

                ++visTilesIter;
            } else {
                // visibleTiles is missing an element present in tileSet
                auto& tile = setTilesIter->second;
                tile->setVisible(false);
                if (tile->getProxyCounter() <= 0) {
                    removeTiles.push_back(tile->getID());
                } else if (tile->isReady()) {
                    m_tiles.push_back(tile);
                }

                ++setTilesIter;
            }
        }
        while (setTilesIter != tiles.end()) {
            // more visibleTiles missing an element present in tileSet
            auto& tile = setTilesIter->second;
            tile->setVisible(false);
            if (tile->getProxyCounter() <= 0) {
                removeTiles.push_back(tile->getID());
            } else if (tile->isReady()) {
                m_tiles.push_back(tile);
            }

            ++setTilesIter;
        }
    }

    {
        while (!removeTiles.empty()) {
            auto tileIter = tiles.find(removeTiles.back());
            removeTiles.pop_back();

            if (tileIter != tiles.end()) {
                if (tileIter->second->getProxyCounter() <= 0) {
                    removeTile(tileSet, tileIter, removeTiles);
                }
            }
        }
    }

    // Update tile distance to map center for load priority
    {
        for (auto& entry : tiles) {
            auto& tile = entry.second;
            auto tileCenter = m_view->getMapProjection().TileCenter(tile->getID());
            tile->setPriority(glm::length2(tileCenter - viewCenter));
        }
    }
}

void TileManager::enqueueLoadTask(const TileSet& tileSet, const TileID& tileID,
                                  const glm::dvec2& viewCenter) {
    // Keep the items sorted by distance
    auto tileCenter = m_view->getMapProjection().TileCenter(tileID);
    double distance = glm::length2(tileCenter - viewCenter);

    auto iter = m_loadTasks.begin();
    while (iter != m_loadTasks.end()) {
        if (std::get<0>(*iter) > distance) {
            break;
        }
        ++iter;
    }
    if (iter == m_loadTasks.end()) {
        m_loadTasks.push_back(std::make_tuple(distance, &tileSet, &tileID));
    } else {
        m_loadTasks.insert(iter, std::make_tuple(distance, &tileSet, &tileID));
    }
}

void TileManager::loadTiles() {

    for (auto& item : m_loadTasks) {
        auto& id = *std::get<2>(item);
        auto& tileSet = *std::get<1>(item);
        auto it = tileSet.tiles.find(id);
        if (it == tileSet.tiles.end()) {
            DBG("[%d, %d, %d] Eeek\n", id.z, id.x, id.y);
            continue;
        }

        auto& tile = it->second;
        auto& source = tileSet.source;

        auto task = std::make_shared<TileTask>(tile, source.get());
        if (source->getTileData(task)) {
            m_dataCallback(std::move(task));

        } else if (m_loadPending < MAX_DOWNLOADS) {
            setTileState(*tile, TileState::loading);

            if (!source->loadTileData(std::move(task), m_dataCallback)) {
                logMsg("ERROR: Loading failed for tile [%d, %d, %d]\n",
                       id.z, id.x, id.y);
                m_loadPending--;
            }
        }
    }

    //DBG("all:%d loading:%d pending:%d cached:%d cache: %fMB\n",
    //    m_tileSet.size(), m_loadTasks.size(),
    //    m_loadPending, m_tileCache->size(),
    //    (double(m_tileCache->getMemoryUsage()) / (1024 * 1024)));

    m_loadTasks.clear();
}

bool TileManager::addTile(TileSet& tileSet, const TileID& _tileID) {

    auto tile = m_tileCache->get(*tileSet.source.get(), _tileID);
    bool fromCache = false;

    if (tile) {
        m_tiles.push_back(tile);
        fromCache = true;
    } else {
        tile = std::shared_ptr<Tile>(new Tile(_tileID, m_view->getMapProjection()));
        //Add Proxy if corresponding proxy MapTile ready
        updateProxyTiles(tileSet, *tile);
    }

    tile->setVisible(true);
    tileSet.tiles.emplace(_tileID, tile);

    return fromCache;
}

void TileManager::removeTile(TileSet& tileSet, std::map<TileID,
                             std::shared_ptr<Tile>>::iterator& _tileIter,
                             std::vector<TileID>& _removes) {

    const TileID& id = _tileIter->first;
    auto& tile = _tileIter->second;

    if (tile->hasState(TileState::loading) &&
        setTileState(*tile, TileState::canceled)) {
        // 1. Remove from Datasource. Make sure to cancel the network request
        // associated with this tile.
        tileSet.source->cancelLoadingTile(id);
    }

    clearProxyTiles(tileSet, *tile, _removes);

    if (tile->hasState(TileState::ready)) {
        // Add to cache
        m_tileCache->put(*tileSet.source.get(), tile);
    }

    // Remove tile from set
    _tileIter = tileSet.tiles.erase(_tileIter);
}

void TileManager::updateProxyTiles(TileSet& tileSet, Tile& _tile) {
    const TileID& _tileID = _tile.getID();
    auto& tiles = tileSet.tiles;

    // Get current parent
    auto parentID = _tileID.getParent();
    {
        const auto& it = tiles.find(parentID);
        if (it != tiles.end()) {
            auto& parent = it->second;
            if (_tile.setProxy(Tile::parent)) {
                parent->incProxyCounter();
                DBG("USE PARENT PROXY\n");

                if (parent->isReady()) {
                    m_tiles.push_back(parent);
                }
            }
            return;
        }
    }
    // Get parent proxy from cache
    {
        auto parent = m_tileCache->get(*tileSet.source.get(), parentID);
        if (parent) {
            _tile.setProxy(Tile::parent);
            parent->incProxyCounter();
            m_tiles.push_back(parent);

            tiles.emplace(parentID, std::move(parent));

            return;
        }
    }

    if (m_view->s_maxZoom > _tileID.z) {
        for (int i = 0; i < 4; i++) {
            auto childID = _tileID.getChild(i);

            const auto& it = tiles.find(childID);
            if (it != tiles.end()) {
                auto& child = it->second;

                if (_tile.setProxy(static_cast<Tile::ProxyID>(1 << i))) {
                    child->incProxyCounter();

                    if (child->isReady()) {
                        m_tiles.push_back(child);
                    }

                    DBG("USE CHILD PROXY\n");
                }
            } else {
                auto child = m_tileCache->get(*tileSet.source.get(), childID);
                if (child) {
                    _tile.setProxy(static_cast<Tile::ProxyID>(1 << i));
                    child->incProxyCounter();
                    m_tiles.push_back(child);

                    tiles.emplace(childID, std::move(child));
                }
            }
        }
    }
}

void TileManager::clearProxyTiles(TileSet& tileSet, Tile& _tile, std::vector<TileID>& _removes) {
    const TileID& _tileID = _tile.getID();
    auto& tiles = tileSet.tiles;

    // Check if parent proxy is present
    if (_tile.unsetProxy(Tile::parent)) {
        TileID parentID(_tileID.getParent());
        auto it = tiles.find(parentID);
        if (it != tiles.end()) {
            auto& parent = it->second;
            parent->decProxyCounter();

            if (parent->getProxyCounter() == 0 && !parent->isVisible()) {
                _removes.push_back(parentID);
            }
        }
    }

    // Check if child proxies are present
    for (int i = 0; i < 4; i++) {
        if (_tile.unsetProxy(static_cast<Tile::ProxyID>(1 << i))) {
            TileID childID(_tileID.getChild(i));
            auto it = tiles.find(childID);

            if (it != tiles.end()) {
                auto& child = it->second;
                child->decProxyCounter();

                if (child->getProxyCounter() == 0 && !child->isVisible()) {
                    _removes.push_back(childID);
                }
            }
        }
    }
}

void TileManager::setCacheSize(size_t _cacheSize) {
    m_tileCache->limitCacheSize(_cacheSize);
}

}
<commit_msg>use std::upper_bound<commit_after>#include "tileManager.h"

#include "data/dataSource.h"
#include "platform.h"
#include "scene/scene.h"
#include "tile/tile.h"
#include "view/view.h"
#include "tileCache.h"

#include "glm/gtx/norm.hpp"

#include <chrono>
#include <algorithm>

#define DBG(...)
//logMsg(__VA_ARGS__)

namespace Tangram {

TileManager::TileManager()
    : m_loadPending(0) {

    // Instantiate workers
    m_workers = std::unique_ptr<TileWorker>(new TileWorker(*this, MAX_WORKERS));

    m_tileCache = std::unique_ptr<TileCache>(new TileCache(DEFAULT_CACHE_SIZE));

    m_dataCallback = [this](std::shared_ptr<TileTask>&& task){
        if (setTileState(*task->tile, TileState::processing)) {
            m_workers->enqueue(std::move(task));
        }
    };
}

TileManager::~TileManager() {
    if (m_workers->isRunning()) {
        m_workers->stop();
    }
    m_tileSets.clear();
}

void TileManager::addDataSource(std::shared_ptr<DataSource>&& dataSource) {
    m_tileSets.push_back({dataSource});
}

void TileManager::tileProcessed(std::shared_ptr<TileTask>&& task) {
    std::lock_guard<std::mutex> lock(m_readyTileMutex);
    m_readyTiles.push_back(std::move(task));
}

bool TileManager::setTileState(Tile& tile, TileState state) {
    std::lock_guard<std::mutex> lock(m_tileStateMutex);

    switch (tile.getState()) {
    case TileState::none:
        if (state == TileState::loading) {
            tile.setState(state);
            m_loadPending++;
            return true;
        }
        if (state == TileState::processing) {
            tile.setState(state);
            return true;
        }
        break;

    case TileState::loading:
        if (state == TileState::processing) {
            tile.setState(state);
            m_loadPending--;
            return true;
        }
        if (state == TileState::canceled) {
            tile.setState(state);
            m_loadPending--;
            return true;
        }
        break;

    case TileState::processing:
        if (state == TileState::ready) {
            tile.setState(state);
            return true;
        }
        break;

    case TileState::canceled:
        // Ignore any state change when tile was canceled
         return false;

    default:
        break;
    }

    if (state == TileState::canceled) {
        tile.setState(state);
        return true;
    }

    logMsg("Wrong state change %d -> %d<<<", tile.getState(), state);
    assert(false);
    return false; // ...
}

void TileManager::clearTileSets() {
    for (auto& tileSet : m_tileSets) {
        for (auto& tile : tileSet.tiles) {
            setTileState(*tile.second, TileState::canceled);
        }
        tileSet.tiles.clear();
    }

    m_tileCache->clear();
    m_loadPending = 0;
}

void TileManager::updateTileSets() {

    m_tileSetChanged = false;
    m_tiles.clear();

    for (auto& tileSet : m_tileSets) {
        updateTileSet(tileSet);
    }

    loadTiles();

    std::sort(m_tiles.begin(), m_tiles.end(), [](auto& a, auto& b){
            return a->getID() < b->getID();
        });

    m_tiles.erase(std::unique(m_tiles.begin(), m_tiles.end()), m_tiles.end());
}

void TileManager::updateTileSet(TileSet& tileSet) {

    auto& tiles = tileSet.tiles;

    std::vector<TileID> removeTiles;

    if (!m_readyTiles.empty()) {
        std::lock_guard<std::mutex> lock(m_readyTileMutex);
        auto it = m_readyTiles.begin();

        while (it != m_readyTiles.end()) {
            auto& task = *it;
            auto& tile = *(task->tile);

            if (tileSet.source.get() == task->source) {

                if (setTileState(tile, TileState::ready)) {
                    clearProxyTiles(tileSet, tile, removeTiles);
                    m_tileSetChanged = true;
                }
                it = m_readyTiles.erase(it);
            } else {
                it++;
            }
        }
    }

    const std::set<TileID>& visibleTiles = m_view->getVisibleTiles();

    glm::dvec2 viewCenter(m_view->getPosition().x, -m_view->getPosition().y);

    if (m_view->changedOnLastUpdate() || m_tileSetChanged) {

        // Loop over visibleTiles and add any needed tiles to tileSet
        auto setTilesIter = tiles.begin();
        auto visTilesIter = visibleTiles.begin();

        while (visTilesIter != visibleTiles.end()) {

            auto& visTileId = *visTilesIter;
            auto& curTileId = setTilesIter == tiles.end() ? NOT_A_TILE : setTilesIter->first;

            if (visTileId == curTileId) {
                auto& tile = setTilesIter->second;

                if (tile->hasState(TileState::none)) {
                    enqueueLoadTask(tileSet, visTileId, viewCenter);
                } else if (tile->isReady()) {
                    m_tiles.push_back(tile);
                }

                tile->setVisible(true);

                // tiles in both sets match
                ++setTilesIter;
                ++visTilesIter;

            } else if (curTileId == NOT_A_TILE || visTileId < curTileId) {
                // tileSet is missing an element present in visibleTiles
                if (!addTile(tileSet, visTileId)) {
                    enqueueLoadTask(tileSet, visTileId, viewCenter);
                }

                ++visTilesIter;
            } else {
                // visibleTiles is missing an element present in tileSet
                auto& tile = setTilesIter->second;
                tile->setVisible(false);
                if (tile->getProxyCounter() <= 0) {
                    removeTiles.push_back(tile->getID());
                } else if (tile->isReady()) {
                    m_tiles.push_back(tile);
                }

                ++setTilesIter;
            }
        }
        while (setTilesIter != tiles.end()) {
            // more visibleTiles missing an element present in tileSet
            auto& tile = setTilesIter->second;
            tile->setVisible(false);
            if (tile->getProxyCounter() <= 0) {
                removeTiles.push_back(tile->getID());
            } else if (tile->isReady()) {
                m_tiles.push_back(tile);
            }

            ++setTilesIter;
        }
    }

    {
        while (!removeTiles.empty()) {
            auto tileIter = tiles.find(removeTiles.back());
            removeTiles.pop_back();

            if (tileIter != tiles.end()) {
                if (tileIter->second->getProxyCounter() <= 0) {
                    removeTile(tileSet, tileIter, removeTiles);
                }
            }
        }
    }

    // Update tile distance to map center for load priority
    {
        for (auto& entry : tiles) {
            auto& tile = entry.second;
            auto tileCenter = m_view->getMapProjection().TileCenter(tile->getID());
            tile->setPriority(glm::length2(tileCenter - viewCenter));
        }
    }
}

void TileManager::enqueueLoadTask(const TileSet& tileSet, const TileID& tileID,
                                  const glm::dvec2& viewCenter) {
    // Keep the items sorted by distance
    auto tileCenter = m_view->getMapProjection().TileCenter(tileID);
    double distance = glm::length2(tileCenter - viewCenter);

    auto it = std::upper_bound(m_loadTasks.begin(), m_loadTasks.end(), distance,
                               [](auto& distance, auto& other){
                                   return distance < std::get<0>(other);
                               });
    m_loadTasks.insert(it, std::make_tuple(distance, &tileSet, &tileID));
}

void TileManager::loadTiles() {

    for (auto& item : m_loadTasks) {
        auto& id = *std::get<2>(item);
        auto& tileSet = *std::get<1>(item);
        auto it = tileSet.tiles.find(id);
        if (it == tileSet.tiles.end()) {
            DBG("[%d, %d, %d] Eeek\n", id.z, id.x, id.y);
            continue;
        }

        auto& tile = it->second;
        auto& source = tileSet.source;

        auto task = std::make_shared<TileTask>(tile, source.get());
        if (source->getTileData(task)) {
            m_dataCallback(std::move(task));

        } else if (m_loadPending < MAX_DOWNLOADS) {
            setTileState(*tile, TileState::loading);

            if (!source->loadTileData(std::move(task), m_dataCallback)) {
                logMsg("ERROR: Loading failed for tile [%d, %d, %d]\n",
                       id.z, id.x, id.y);
                m_loadPending--;
            }
        }
    }

    //DBG("all:%d loading:%d pending:%d cached:%d cache: %fMB\n",
    //    m_tileSet.size(), m_loadTasks.size(),
    //    m_loadPending, m_tileCache->size(),
    //    (double(m_tileCache->getMemoryUsage()) / (1024 * 1024)));

    m_loadTasks.clear();
}

bool TileManager::addTile(TileSet& tileSet, const TileID& _tileID) {

    auto tile = m_tileCache->get(*tileSet.source.get(), _tileID);
    bool fromCache = false;

    if (tile) {
        m_tiles.push_back(tile);
        fromCache = true;
    } else {
        tile = std::shared_ptr<Tile>(new Tile(_tileID, m_view->getMapProjection()));
        //Add Proxy if corresponding proxy MapTile ready
        updateProxyTiles(tileSet, *tile);
    }

    tile->setVisible(true);
    tileSet.tiles.emplace(_tileID, tile);

    return fromCache;
}

void TileManager::removeTile(TileSet& tileSet, std::map<TileID,
                             std::shared_ptr<Tile>>::iterator& _tileIter,
                             std::vector<TileID>& _removes) {

    const TileID& id = _tileIter->first;
    auto& tile = _tileIter->second;

    if (tile->hasState(TileState::loading) &&
        setTileState(*tile, TileState::canceled)) {
        // 1. Remove from Datasource. Make sure to cancel the network request
        // associated with this tile.
        tileSet.source->cancelLoadingTile(id);
    }

    clearProxyTiles(tileSet, *tile, _removes);

    if (tile->hasState(TileState::ready)) {
        // Add to cache
        m_tileCache->put(*tileSet.source.get(), tile);
    }

    // Remove tile from set
    _tileIter = tileSet.tiles.erase(_tileIter);
}

void TileManager::updateProxyTiles(TileSet& tileSet, Tile& _tile) {
    const TileID& _tileID = _tile.getID();
    auto& tiles = tileSet.tiles;

    // Get current parent
    auto parentID = _tileID.getParent();
    {
        const auto& it = tiles.find(parentID);
        if (it != tiles.end()) {
            auto& parent = it->second;
            if (_tile.setProxy(Tile::parent)) {
                parent->incProxyCounter();
                DBG("USE PARENT PROXY\n");

                if (parent->isReady()) {
                    m_tiles.push_back(parent);
                }
            }
            return;
        }
    }
    // Get parent proxy from cache
    {
        auto parent = m_tileCache->get(*tileSet.source.get(), parentID);
        if (parent) {
            _tile.setProxy(Tile::parent);
            parent->incProxyCounter();
            m_tiles.push_back(parent);

            tiles.emplace(parentID, std::move(parent));

            return;
        }
    }

    if (m_view->s_maxZoom > _tileID.z) {
        for (int i = 0; i < 4; i++) {
            auto childID = _tileID.getChild(i);

            const auto& it = tiles.find(childID);
            if (it != tiles.end()) {
                auto& child = it->second;

                if (_tile.setProxy(static_cast<Tile::ProxyID>(1 << i))) {
                    child->incProxyCounter();

                    if (child->isReady()) {
                        m_tiles.push_back(child);
                    }

                    DBG("USE CHILD PROXY\n");
                }
            } else {
                auto child = m_tileCache->get(*tileSet.source.get(), childID);
                if (child) {
                    _tile.setProxy(static_cast<Tile::ProxyID>(1 << i));
                    child->incProxyCounter();
                    m_tiles.push_back(child);

                    tiles.emplace(childID, std::move(child));
                }
            }
        }
    }
}

void TileManager::clearProxyTiles(TileSet& tileSet, Tile& _tile, std::vector<TileID>& _removes) {
    const TileID& _tileID = _tile.getID();
    auto& tiles = tileSet.tiles;

    // Check if parent proxy is present
    if (_tile.unsetProxy(Tile::parent)) {
        TileID parentID(_tileID.getParent());
        auto it = tiles.find(parentID);
        if (it != tiles.end()) {
            auto& parent = it->second;
            parent->decProxyCounter();

            if (parent->getProxyCounter() == 0 && !parent->isVisible()) {
                _removes.push_back(parentID);
            }
        }
    }

    // Check if child proxies are present
    for (int i = 0; i < 4; i++) {
        if (_tile.unsetProxy(static_cast<Tile::ProxyID>(1 << i))) {
            TileID childID(_tileID.getChild(i));
            auto it = tiles.find(childID);

            if (it != tiles.end()) {
                auto& child = it->second;
                child->decProxyCounter();

                if (child->getProxyCounter() == 0 && !child->isVisible()) {
                    _removes.push_back(childID);
                }
            }
        }
    }
}

void TileManager::setCacheSize(size_t _cacheSize) {
    m_tileCache->limitCacheSize(_cacheSize);
}

}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.1  1999/11/09 01:02:14  twl
 * Initial revision
 *
 * Revision 1.3  1999/11/08 20:42:25  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include    <util/PlatformUtils.hpp>
#include    <util/XMLString.hpp>
#include    <util/URL.hpp>
#include    <internal/URLInputSource.hpp>
#include    <internal/XMLScanner.hpp>
#include    <validators/DTD/DTDValidator.hpp>
#include    "ParserTest.hpp"

// ---------------------------------------------------------------------------
//  Global data
//
//  errStrm
//  outStrm
//      The streams we use to output our test data and error info. These are
//      simple classes used just for XML4C2 samples and debug. They are not
//      sufficient for real applications, nor are they supported for
//      production code use. They merely provide a simple and portable means
//      to output the Unicode data from the parser on the local host.
// ---------------------------------------------------------------------------
XMLStdErr   errStrm;
XMLStdOut   outStrm;

// ---------------------------------------------------------------------------
//  Program entry point
// ---------------------------------------------------------------------------
int main(int argC, char** argV)
{
    // Init the XML platform
    try
    {
        XMLPlatformUtils::Initialize();
    }

    catch(const XMLException& toCatch)
    {
        errStrm << "Error during platform init! Message:\n"
                << toCatch.getMessage() << EndLn;
        return 1;
    }

    //
    //  Create our test parser object. This guy implements the internal event
    //  APIs and is plugged into the scanner.
    //
    TestParser parserTest;

    // Figure out the parameters
    bool doValidation = false;
    bool doNamespaces = false;
    bool keepGoing = false;
    XMLCh*  urlPath = 0;
    for (int index = 1; index < argC; index++)
    {
        if (!XMLString::compareIString(argV[index], "/Debug"))
            parserTest.setOutputType(OutputType_Debug);
        else if (!XMLString::compareIString(argV[index], "/Validate"))
            doValidation = true;
        else if (!XMLString::compareIString(argV[index], "/Namespaces"))
        {
            doNamespaces = true;
            parserTest.setDoNamespaces(true);
        }
        else if (!XMLString::compareIString(argV[index], "/XML"))
            parserTest.setOutputType(OutputType_XML);
        else if (!XMLString::compareIString(argV[index], "/IntDTD"))
            parserTest.setShowIntDTD(true);
        else if (!XMLString::compareIString(argV[index], "/ShowWarnings"))
            parserTest.setShowWarnings(true);
        else if (!XMLString::compareIString(argV[index], "/ShowErrLoc"))
            parserTest.setShowErrLoc(true);
        else if (!XMLString::compareIString(argV[index], "/JCCanon"))
            parserTest.setOutputType(OutputType_JCCanon);
        else if (!XMLString::compareIString(argV[index], "/SunCanon"))
            parserTest.setOutputType(OutputType_SunCanon);
        else if (!XMLString::compareIString(argV[index], "/KeepGoing"))
            keepGoing = true;
        else if (!XMLString::compareNIString(argV[index], "/URL=", 5))
            urlPath = XMLString::transcode(&argV[index][5]);
        else
            errStrm << "Unknown parameter: " << argV[index] << EndLn;
    }

    // We have to have a URL to work on
    if (!urlPath)
    {
        errStrm << "A URL must be provided, /URL=xxxx" << EndLn;
        return 1;
    }

    //
    //  Create a validator of the correct type so that we can install it
    //  on the scanner.
    //
    //  <TBD> Later, when Schema validators exist, we'll have a parameter
    //  to select one or the other
    //
    XMLValidator* validator = 0;
    DTDValidator* dtdVal = new DTDValidator(&parserTest);
    dtdVal->setDocTypeHandler(&parserTest);
    validator = dtdVal;

    // And now create the scanner and give it all the handlers
    XMLScanner scanner
    (
        &parserTest
        , 0
        , &parserTest
        , validator
    );

    // Set the scanner flags that we were told to
    scanner.setDoValidation(doValidation);
    scanner.setDoNamespaces(doNamespaces);
    scanner.setExitOnFirstFatal(!keepGoing);

    // Tell the parser about the scanner
    parserTest.setScanner(&scanner);

    try
    {
        URLInputSource src(urlPath);
        scanner.scanDocument(src);
    }

    catch(const XMLException& toCatch)
    {
        outStrm << "Exception during scan:\n    "
                << toCatch.getMessage()
                << EndLn;
    }

    return 0;
}
<commit_msg>Changes for the new URL and InputSource changes.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.2  2000/01/12 00:29:49  roddey
 * Changes for the new URL and InputSource changes.
 *
 * Revision 1.1.1.1  1999/11/09 01:02:14  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:42:25  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include    <util/PlatformUtils.hpp>
#include    <util/XMLString.hpp>
#include    <util/URL.hpp>
#include    <internal/XMLScanner.hpp>
#include    <validators/DTD/DTDValidator.hpp>
#include    "ParserTest.hpp"

// ---------------------------------------------------------------------------
//  Global data
//
//  errStrm
//  outStrm
//      The streams we use to output our test data and error info. These are
//      simple classes used just for XML4C2 samples and debug. They are not
//      sufficient for real applications, nor are they supported for
//      production code use. They merely provide a simple and portable means
//      to output the Unicode data from the parser on the local host.
// ---------------------------------------------------------------------------
XMLStdErr   errStrm;
XMLStdOut   outStrm;

// ---------------------------------------------------------------------------
//  Program entry point
// ---------------------------------------------------------------------------
int main(int argC, char** argV)
{
    // Init the XML platform
    try
    {
        XMLPlatformUtils::Initialize();
    }

    catch(const XMLException& toCatch)
    {
        errStrm << "Error during platform init! Message:\n"
                << toCatch.getMessage() << EndLn;
        return 1;
    }

    //
    //  Create our test parser object. This guy implements the internal event
    //  APIs and is plugged into the scanner.
    //
    TestParser parserTest;

    // Figure out the parameters
    bool doValidation = false;
    bool doNamespaces = false;
    bool keepGoing = false;
    XMLCh*  urlPath = 0;
    for (int index = 1; index < argC; index++)
    {
        if (!XMLString::compareIString(argV[index], "/Debug"))
            parserTest.setOutputType(OutputType_Debug);
        else if (!XMLString::compareIString(argV[index], "/Validate"))
            doValidation = true;
        else if (!XMLString::compareIString(argV[index], "/Namespaces"))
        {
            doNamespaces = true;
            parserTest.setDoNamespaces(true);
        }
        else if (!XMLString::compareIString(argV[index], "/XML"))
            parserTest.setOutputType(OutputType_XML);
        else if (!XMLString::compareIString(argV[index], "/IntDTD"))
            parserTest.setShowIntDTD(true);
        else if (!XMLString::compareIString(argV[index], "/ShowWarnings"))
            parserTest.setShowWarnings(true);
        else if (!XMLString::compareIString(argV[index], "/ShowErrLoc"))
            parserTest.setShowErrLoc(true);
        else if (!XMLString::compareIString(argV[index], "/JCCanon"))
            parserTest.setOutputType(OutputType_JCCanon);
        else if (!XMLString::compareIString(argV[index], "/SunCanon"))
            parserTest.setOutputType(OutputType_SunCanon);
        else if (!XMLString::compareIString(argV[index], "/KeepGoing"))
            keepGoing = true;
        else if (!XMLString::compareNIString(argV[index], "/URL=", 5))
            urlPath = XMLString::transcode(&argV[index][5]);
        else
            errStrm << "Unknown parameter: " << argV[index] << EndLn;
    }

    // We have to have a URL to work on
    if (!urlPath)
    {
        errStrm << "A URL must be provided, /URL=xxxx" << EndLn;
        return 1;
    }

    //
    //  Create a validator of the correct type so that we can install it
    //  on the scanner.
    //
    //  <TBD> Later, when Schema validators exist, we'll have a parameter
    //  to select one or the other
    //
    XMLValidator* validator = 0;
    DTDValidator* dtdVal = new DTDValidator(&parserTest);
    dtdVal->setDocTypeHandler(&parserTest);
    validator = dtdVal;

    // And now create the scanner and give it all the handlers
    XMLScanner scanner
    (
        &parserTest
        , 0
        , &parserTest
        , validator
    );

    // Set the scanner flags that we were told to
    scanner.setDoValidation(doValidation);
    scanner.setDoNamespaces(doNamespaces);
    scanner.setExitOnFirstFatal(!keepGoing);

    // Tell the parser about the scanner
    parserTest.setScanner(&scanner);

    try
    {
        scanner.scanDocument(urlPath);
    }

    catch(const XMLException& toCatch)
    {
        outStrm << "Exception during scan:\n    "
                << toCatch.getMessage()
                << EndLn;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*=====================================================================

PIXHAWK Micro Air Vehicle Flying Robotics Toolkit

(c) 2009, 2010 PIXHAWK PROJECT  <http://pixhawk.ethz.ch>

This file is part of the PIXHAWK project

    PIXHAWK is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PIXHAWK 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PIXHAWK. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Waypoint list widget
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *   @author Benjamin Knecht <mavteam@student.ethz.ch>
 *   @author Petri Tanskanen <mavteam@student.ethz.ch>
 *
 */

#include "WaypointList.h"
#include "ui_WaypointList.h"
#include <UASInterface.h>
#include <UASManager.h>
#include <QDebug>
#include <QFileDialog>

WaypointList::WaypointList(QWidget *parent, UASInterface* uas) :
        QWidget(parent),
        uas(NULL),
        m_ui(new Ui::WaypointList)
{
    m_ui->setupUi(this);

    listLayout = new QVBoxLayout(m_ui->listWidget);
    listLayout->setSpacing(6);
    listLayout->setMargin(0);
    listLayout->setAlignment(Qt::AlignTop);
    m_ui->listWidget->setLayout(listLayout);

    wpViews = QMap<Waypoint*, WaypointView*>();

    this->uas = NULL;

    // ADD WAYPOINT
    // Connect add action, set right button icon and connect action to this class
    connect(m_ui->addButton, SIGNAL(clicked()), m_ui->actionAddWaypoint, SIGNAL(triggered()));
    connect(m_ui->actionAddWaypoint, SIGNAL(triggered()), this, SLOT(add()));

    // SEND WAYPOINTS
    connect(m_ui->transmitButton, SIGNAL(clicked()), this, SLOT(transmit()));

    // REQUEST WAYPOINTS
    connect(m_ui->readButton, SIGNAL(clicked()), this, SLOT(read()));

    // SAVE/LOAD WAYPOINTS
    connect(m_ui->saveButton, SIGNAL(clicked()), this, SLOT(saveWaypoints()));
    connect(m_ui->loadButton, SIGNAL(clicked()), this, SLOT(loadWaypoints()));

    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setUAS(UASInterface*)));

    // STATUS LABEL
    updateStatusLabel("");

    // SET UAS AFTER ALL SIGNALS/SLOTS ARE CONNECTED
    setUAS(uas);
}

WaypointList::~WaypointList()
{
    delete m_ui;
}

void WaypointList::updateStatusLabel(const QString &string)
{
    m_ui->statusLabel->setText(string);
}

void WaypointList::setUAS(UASInterface* uas)
{
    if (this->uas == NULL && uas != NULL)
    {
        this->uas = uas;

        connect(&uas->getWaypointManager(), SIGNAL(updateStatusString(const QString &)),                                this, SLOT(updateStatusLabel(const QString &)));
        connect(&uas->getWaypointManager(), SIGNAL(waypointUpdated(int,quint16,double,double,double,double,bool,bool,double,int)), this, SLOT(setWaypoint(int,quint16,double,double,double,double,bool,bool,double,int)));
        connect(&uas->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)),                                    this, SLOT(currentWaypointChanged(quint16)));

        connect(this, SIGNAL(sendWaypoints(const QVector<Waypoint*> &)),    &uas->getWaypointManager(), SLOT(sendWaypoints(const QVector<Waypoint*> &)));
        connect(this, SIGNAL(requestWaypoints()),                           &uas->getWaypointManager(), SLOT(requestWaypoints()));
        connect(this, SIGNAL(clearWaypointList()),                          &uas->getWaypointManager(), SLOT(clearWaypointList()));
    }
}

void WaypointList::setWaypoint(int uasId, quint16 id, double x, double y, double z, double yaw, bool autocontinue, bool current, double orbit, int holdTime)
{
    if (uasId == this->uas->getUASID())
    {
        Waypoint* wp = new Waypoint(id, x, y, z, yaw, autocontinue, current, orbit, holdTime);
        addWaypoint(wp);
    }
}

void WaypointList::waypointReached(UASInterface* uas, quint16 waypointId)
{
    Q_UNUSED(uas);
    qDebug() << "Waypoint reached: " << waypointId;

    updateStatusLabel(QString("Waypoint %1 reached.").arg(waypointId));
}

void WaypointList::currentWaypointChanged(quint16 seq)
{
    if (seq < waypoints.size())
    {
        for(int i = 0; i < waypoints.size(); i++)
        {
            WaypointView* widget = wpViews.find(waypoints[i]).value();

            if (waypoints[i]->getId() == seq)
            {
                waypoints[i]->setCurrent(true);
                widget->setCurrent(true);
            }
            else
            {
                waypoints[i]->setCurrent(false);
                widget->setCurrent(false);
            }
        }
        redrawList();
    }
}

void WaypointList::read()
{
    while(waypoints.size()>0)
    {
        removeWaypoint(waypoints[0]);
    }

    emit requestWaypoints();
}

void WaypointList::transmit()
{
    emit sendWaypoints(waypoints);
    //emit requestWaypoints(); FIXME
}

void WaypointList::add()
{
    // Only add waypoints if UAS is present
    if (uas)
    {
        if (waypoints.size() > 0)
        {
            Waypoint *last = waypoints.at(waypoints.size()-1);
            addWaypoint(new Waypoint(waypoints.size(), last->getX(), last->getY(), last->getZ(), last->getYaw(), last->getAutoContinue(), last->getCurrent(), last->getOrbit(), last->getHoldTime()));
        }
        else
        {
            addWaypoint(new Waypoint(waypoints.size(), 1.1, 1.1, -0.8, 0.0, true, true, 0.1, 1000));
        }
    }
}

void WaypointList::addWaypoint(Waypoint* wp)
{
    waypoints.push_back(wp);
    if (!wpViews.contains(wp))
    {
        WaypointView* wpview = new WaypointView(wp, this);
        wpViews.insert(wp, wpview);
        listLayout->addWidget(wpViews.value(wp));
        connect(wpview, SIGNAL(moveDownWaypoint(Waypoint*)), this, SLOT(moveDown(Waypoint*)));
        connect(wpview, SIGNAL(moveUpWaypoint(Waypoint*)), this, SLOT(moveUp(Waypoint*)));
        connect(wpview, SIGNAL(removeWaypoint(Waypoint*)), this, SLOT(removeWaypoint(Waypoint*)));
        connect(wpview, SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointChanged(quint16)));
    }
}

void WaypointList::redrawList()
{
    // Clear list layout
    if (!wpViews.empty())
    {
        QMapIterator<Waypoint*,WaypointView*> viewIt(wpViews);
        viewIt.toFront();
        while(viewIt.hasNext())
        {
            viewIt.next();
            listLayout->removeWidget(viewIt.value());
        }
        // Re-add waypoints
        for(int i = 0; i < waypoints.size(); i++)
        {
            listLayout->addWidget(wpViews.value(waypoints[i]));
        }
    }
}

void WaypointList::moveUp(Waypoint* wp)
{
    int id = wp->getId();
    if (waypoints.size() > 1 && waypoints.size() > id)
    {
        Waypoint* temp = waypoints[id];
        if (id > 0)
        {
            waypoints[id] = waypoints[id-1];
            waypoints[id-1] = temp;
            waypoints[id-1]->setId(id-1);
            waypoints[id]->setId(id);
        }
        else
        {
            waypoints[id] = waypoints[waypoints.size()-1];
            waypoints[waypoints.size()-1] = temp;
            waypoints[waypoints.size()-1]->setId(waypoints.size()-1);
            waypoints[id]->setId(id);
        }
        redrawList();
    }
}

void WaypointList::moveDown(Waypoint* wp)
{
    int id = wp->getId();
    if (waypoints.size() > 1 && waypoints.size() > id)
    {
        Waypoint* temp = waypoints[id];
        if (id != waypoints.size()-1)
        {
            waypoints[id] = waypoints[id+1];
            waypoints[id+1] = temp;
            waypoints[id+1]->setId(id+1);
            waypoints[id]->setId(id);
        }
        else
        {
            waypoints[id] = waypoints[0];
            waypoints[0] = temp;
            waypoints[0]->setId(0);
            waypoints[id]->setId(id);
        }
        redrawList();
    }
}

void WaypointList::removeWaypoint(Waypoint* wp)
{
    // Delete from list
    if (wp != NULL)
    {
        waypoints.remove(wp->getId());
        for(int i = wp->getId(); i < waypoints.size(); i++)
        {
            waypoints[i]->setId(i);
        }

        // Remove from view
        WaypointView* widget = wpViews.find(wp).value();
        wpViews.remove(wp);
        widget->hide();
        listLayout->removeWidget(widget);
        delete wp;
    }
}

void WaypointList::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void WaypointList::saveWaypoints()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./waypoints.txt", tr("Waypoint File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream in(&file);
    for (int i = 0; i < waypoints.size(); i++)
    {
        Waypoint* wp = waypoints[i];
        in << "\t" << wp->getId() << "\t" << wp->getX() << "\t" << wp->getY()  << "\t" << wp->getZ()  << "\t" << wp->getYaw()  << "\t" << wp->getAutoContinue() << "\t" << wp->getCurrent() << "\t" << wp->getOrbit() << "\t" << wp->getHoldTime() << "\n";
        in.flush();
    }
    file.close();
}

void WaypointList::loadWaypoints()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Waypoint File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    while(waypoints.size()>0)
    {
        removeWaypoint(waypoints[0]);
    }

    QTextStream in(&file);
    while (!in.atEnd())
    {
        QStringList wpParams = in.readLine().split("\t");
        if (wpParams.size() == 10)
            addWaypoint(new Waypoint(wpParams[1].toInt(), wpParams[2].toDouble(), wpParams[3].toDouble(), wpParams[4].toDouble(), wpParams[5].toDouble(), (wpParams[6].toInt() == 1 ? true : false), (wpParams[7].toInt() == 1 ? true : false), wpParams[8].toDouble(), wpParams[9].toInt()));
    }
    file.close();
}

<commit_msg>fixed waypoint interface<commit_after>/*=====================================================================

PIXHAWK Micro Air Vehicle Flying Robotics Toolkit

(c) 2009, 2010 PIXHAWK PROJECT  <http://pixhawk.ethz.ch>

This file is part of the PIXHAWK project

    PIXHAWK is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PIXHAWK 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PIXHAWK. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Waypoint list widget
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *   @author Benjamin Knecht <mavteam@student.ethz.ch>
 *   @author Petri Tanskanen <mavteam@student.ethz.ch>
 *
 */

#include "WaypointList.h"
#include "ui_WaypointList.h"
#include <UASInterface.h>
#include <UASManager.h>
#include <QDebug>
#include <QFileDialog>

WaypointList::WaypointList(QWidget *parent, UASInterface* uas) :
        QWidget(parent),
        uas(NULL),
        m_ui(new Ui::WaypointList)
{
    m_ui->setupUi(this);

    listLayout = new QVBoxLayout(m_ui->listWidget);
    listLayout->setSpacing(6);
    listLayout->setMargin(0);
    listLayout->setAlignment(Qt::AlignTop);
    m_ui->listWidget->setLayout(listLayout);

    wpViews = QMap<Waypoint*, WaypointView*>();

    this->uas = NULL;

    // ADD WAYPOINT
    // Connect add action, set right button icon and connect action to this class
    connect(m_ui->addButton, SIGNAL(clicked()), m_ui->actionAddWaypoint, SIGNAL(triggered()));
    connect(m_ui->actionAddWaypoint, SIGNAL(triggered()), this, SLOT(add()));

    // SEND WAYPOINTS
    connect(m_ui->transmitButton, SIGNAL(clicked()), this, SLOT(transmit()));

    // REQUEST WAYPOINTS
    connect(m_ui->readButton, SIGNAL(clicked()), this, SLOT(read()));

    // SAVE/LOAD WAYPOINTS
    connect(m_ui->saveButton, SIGNAL(clicked()), this, SLOT(saveWaypoints()));
    connect(m_ui->loadButton, SIGNAL(clicked()), this, SLOT(loadWaypoints()));

    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setUAS(UASInterface*)));

    // STATUS LABEL
    updateStatusLabel("");

    // SET UAS AFTER ALL SIGNALS/SLOTS ARE CONNECTED
    setUAS(uas);
}

WaypointList::~WaypointList()
{
    delete m_ui;
}

void WaypointList::updateStatusLabel(const QString &string)
{
    m_ui->statusLabel->setText(string);
}

void WaypointList::setUAS(UASInterface* uas)
{
    if (this->uas == NULL && uas != NULL)
    {
        this->uas = uas;

        connect(&uas->getWaypointManager(), SIGNAL(updateStatusString(const QString &)),                                this, SLOT(updateStatusLabel(const QString &)));
        connect(&uas->getWaypointManager(), SIGNAL(waypointUpdated(int,quint16,double,double,double,double,bool,bool,double,int)), this, SLOT(setWaypoint(int,quint16,double,double,double,double,bool,bool,double,int)));
        connect(&uas->getWaypointManager(), SIGNAL(currentWaypointChanged(quint16)),                                    this, SLOT(currentWaypointChanged(quint16)));

        connect(this, SIGNAL(sendWaypoints(const QVector<Waypoint*> &)),    &uas->getWaypointManager(), SLOT(sendWaypoints(const QVector<Waypoint*> &)));
        connect(this, SIGNAL(requestWaypoints()),                           &uas->getWaypointManager(), SLOT(requestWaypoints()));
        connect(this, SIGNAL(clearWaypointList()),                          &uas->getWaypointManager(), SLOT(clearWaypointList()));
    }
}

void WaypointList::setWaypoint(int uasId, quint16 id, double x, double y, double z, double yaw, bool autocontinue, bool current, double orbit, int holdTime)
{
    if (uasId == this->uas->getUASID())
    {
        Waypoint* wp = new Waypoint(id, x, y, z, yaw, autocontinue, current, orbit, holdTime);
        addWaypoint(wp);
    }
}

void WaypointList::waypointReached(UASInterface* uas, quint16 waypointId)
{
    Q_UNUSED(uas);
    qDebug() << "Waypoint reached: " << waypointId;

    updateStatusLabel(QString("Waypoint %1 reached.").arg(waypointId));
}

void WaypointList::currentWaypointChanged(quint16 seq)
{
    if (seq < waypoints.size())
    {
        for(int i = 0; i < waypoints.size(); i++)
        {
            WaypointView* widget = wpViews.find(waypoints[i]).value();

            if (waypoints[i]->getId() == seq)
            {
                waypoints[i]->setCurrent(true);
                widget->setCurrent(true);
            }
            else
            {
                waypoints[i]->setCurrent(false);
                widget->setCurrent(false);
            }
        }
        redrawList();
    }
}

void WaypointList::read()
{
    while(waypoints.size()>0)
    {
        removeWaypoint(waypoints[0]);
    }

    emit requestWaypoints();
}

void WaypointList::transmit()
{
    emit sendWaypoints(waypoints);
    //emit requestWaypoints(); FIXME
}

void WaypointList::add()
{
    // Only add waypoints if UAS is present
    if (uas)
    {
        if (waypoints.size() > 0)
        {
            Waypoint *last = waypoints.at(waypoints.size()-1);
            addWaypoint(new Waypoint(waypoints.size(), last->getX(), last->getY(), last->getZ(), last->getYaw(), last->getAutoContinue(), false, last->getOrbit(), last->getHoldTime()));
        }
        else
        {
            addWaypoint(new Waypoint(waypoints.size(), 1.1, 1.1, -0.8, 0.0, true, true, 0.1, 1000));
        }
    }
}

void WaypointList::addWaypoint(Waypoint* wp)
{
    waypoints.push_back(wp);
    if (!wpViews.contains(wp))
    {
        WaypointView* wpview = new WaypointView(wp, this);
        wpViews.insert(wp, wpview);
        listLayout->addWidget(wpViews.value(wp));
        connect(wpview, SIGNAL(moveDownWaypoint(Waypoint*)), this, SLOT(moveDown(Waypoint*)));
        connect(wpview, SIGNAL(moveUpWaypoint(Waypoint*)), this, SLOT(moveUp(Waypoint*)));
        connect(wpview, SIGNAL(removeWaypoint(Waypoint*)), this, SLOT(removeWaypoint(Waypoint*)));
        connect(wpview, SIGNAL(currentWaypointChanged(quint16)), this, SLOT(currentWaypointChanged(quint16)));
    }
}

void WaypointList::redrawList()
{
    // Clear list layout
    if (!wpViews.empty())
    {
        QMapIterator<Waypoint*,WaypointView*> viewIt(wpViews);
        viewIt.toFront();
        while(viewIt.hasNext())
        {
            viewIt.next();
            listLayout->removeWidget(viewIt.value());
        }
        // Re-add waypoints
        for(int i = 0; i < waypoints.size(); i++)
        {
            listLayout->addWidget(wpViews.value(waypoints[i]));
        }
    }
}

void WaypointList::moveUp(Waypoint* wp)
{
    int id = wp->getId();
    if (waypoints.size() > 1 && waypoints.size() > id)
    {
        Waypoint* temp = waypoints[id];
        if (id > 0)
        {
            waypoints[id] = waypoints[id-1];
            waypoints[id-1] = temp;
            waypoints[id-1]->setId(id-1);
            waypoints[id]->setId(id);
        }
        else
        {
            waypoints[id] = waypoints[waypoints.size()-1];
            waypoints[waypoints.size()-1] = temp;
            waypoints[waypoints.size()-1]->setId(waypoints.size()-1);
            waypoints[id]->setId(id);
        }
        redrawList();
    }
}

void WaypointList::moveDown(Waypoint* wp)
{
    int id = wp->getId();
    if (waypoints.size() > 1 && waypoints.size() > id)
    {
        Waypoint* temp = waypoints[id];
        if (id != waypoints.size()-1)
        {
            waypoints[id] = waypoints[id+1];
            waypoints[id+1] = temp;
            waypoints[id+1]->setId(id+1);
            waypoints[id]->setId(id);
        }
        else
        {
            waypoints[id] = waypoints[0];
            waypoints[0] = temp;
            waypoints[0]->setId(0);
            waypoints[id]->setId(id);
        }
        redrawList();
    }
}

void WaypointList::removeWaypoint(Waypoint* wp)
{
    // Delete from list
    if (wp != NULL)
    {
        waypoints.remove(wp->getId());
        for(int i = wp->getId(); i < waypoints.size(); i++)
        {
            waypoints[i]->setId(i);
        }

        // Remove from view
        WaypointView* widget = wpViews.find(wp).value();
        wpViews.remove(wp);
        widget->hide();
        listLayout->removeWidget(widget);
        delete wp;
    }
}

void WaypointList::changeEvent(QEvent *e)
{
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void WaypointList::saveWaypoints()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "./waypoints.txt", tr("Waypoint File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream in(&file);
    for (int i = 0; i < waypoints.size(); i++)
    {
        Waypoint* wp = waypoints[i];
        in << "\t" << wp->getId() << "\t" << wp->getX() << "\t" << wp->getY()  << "\t" << wp->getZ()  << "\t" << wp->getYaw()  << "\t" << wp->getAutoContinue() << "\t" << wp->getCurrent() << "\t" << wp->getOrbit() << "\t" << wp->getHoldTime() << "\n";
        in.flush();
    }
    file.close();
}

void WaypointList::loadWaypoints()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Waypoint File (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    while(waypoints.size()>0)
    {
        removeWaypoint(waypoints[0]);
    }

    QTextStream in(&file);
    while (!in.atEnd())
    {
        QStringList wpParams = in.readLine().split("\t");
        if (wpParams.size() == 10)
            addWaypoint(new Waypoint(wpParams[1].toInt(), wpParams[2].toDouble(), wpParams[3].toDouble(), wpParams[4].toDouble(), wpParams[5].toDouble(), (wpParams[6].toInt() == 1 ? true : false), (wpParams[7].toInt() == 1 ? true : false), wpParams[8].toDouble(), wpParams[9].toInt()));
    }
    file.close();
}

<|endoftext|>


<commit_before>#include "multiverso/util/allocator.h"

#include "multiverso/util/log.h"
#include "multiverso/util/configure.h"

namespace multiverso {

MV_DEFINE_int(allocator_alignment, 16, "alignment for align malloc");

inline char* AlignMalloc(size_t size) {
#ifdef _MSC_VER
  return (char*)_aligned_malloc(size,
    MV_CONFIG_allocator_alignment);
#else
  void *data;
  CHECK(posix_memalign(&data,
    MV_CONFIG_allocator_alignment, size) == 0);
  return (char*)data;
#endif
}

inline void AlignFree(char *data) {
#ifdef _MSC_VER
  _aligned_free(data);
#else
  free(data);
#endif
}

inline FreeList::FreeList(size_t size) :
size_(size) {
  free_ = new MemoryBlock(size, this);
}

FreeList::~FreeList() {
  MemoryBlock*move = free_, *next;
  while (move) {
    next = move->next;
    delete move;
    move = next;
  }
}

inline char* FreeList::Pop() {
  std::lock_guard<std::mutex> lock(mutex_);
  if (free_ == nullptr) {
    free_ = new MemoryBlock(size_, this);
  }
  char* data = free_->data();
  free_ = free_->next;
  return data;
}

inline void FreeList::Push(MemoryBlock*block) {
  std::lock_guard<std::mutex> lock(mutex_);
  block->next = free_;
  free_ = block;
}

inline MemoryBlock::MemoryBlock(size_t size, FreeList* list) :
next(nullptr), ref_(0) {
  data_ = AlignMalloc(size + header_size_);
  *(FreeList**)(data_) = list;
  *(MemoryBlock**)(data_ + g_pointer_size) = this;
}

MemoryBlock::~MemoryBlock() {
  AlignFree(data_);
}

inline void MemoryBlock::Unlink() {
  if ((--ref_) == 0) {
    (*(FreeList**)data_)->Push(this);
  }
}

inline char* MemoryBlock::data() {
  ++ref_;
  return data_ + header_size_;
}

inline void MemoryBlock::Link() {
  ++ref_;
}

char* SmartAllocator::Alloc(size_t size) {
  if (size <= 32) {
    size = 32;
  }
  else { // 2^n
    size -= 1;
    size |= size >> 32;
    size |= size >> 16;
    size |= size >> 8;
    size |= size >> 4;
    size |= size >> 2;
    size |= size >> 1;
    size += 1;
  }

  std::unique_lock<std::mutex> lock(mutex_);
  if (pools_[size] == nullptr) {
    pools_[size] = new FreeList(size);
  }
  lock.unlock();

  return pools_[size]->Pop();
}

void SmartAllocator::Free(char *data) {
  (*(MemoryBlock**)(data - g_pointer_size))->Unlink();
}

void SmartAllocator::Refer(char *data) {
  (*(MemoryBlock**)(data - g_pointer_size))->Link();
}

SmartAllocator::~SmartAllocator() {
  Log::Debug("~SmartAllocator, final pool size: %d\n", pools_.size());
  for (auto i : pools_) {
    delete i.second;
  }
}

char* Allocator::Alloc(size_t size) {
  char* data = AlignMalloc(size + header_size_);
  // record ref
  *(std::atomic<int>**)data = new std::atomic<int>(1);
  return data + header_size_;
}

void Allocator::Free(char* data) {
  data -= header_size_;
  if (--(**(std::atomic<int>**)data) == 0) {
    delete *(std::atomic<int>**)data;
    AlignFree(data);
  }
}

void Allocator::Refer(char* data) {
  ++(**(std::atomic<int>**)(data - header_size_));
}

MV_DEFINE_string(allocator_type, "smart", "use smart allocator by default");
Allocator* Allocator::Get() {
  if (MV_CONFIG_allocator_type == "smart") {
    static SmartAllocator allocator_;
    return &allocator_;
  }
  static Allocator allocator_;
  return &allocator_;
}

} // namespace multiverso
<commit_msg>Little change<commit_after>#include "multiverso/util/allocator.h"

#include "multiverso/util/log.h"
#include "multiverso/util/configure.h"

namespace multiverso {

MV_DEFINE_int(allocator_alignment, 16, "alignment for align malloc");

inline char* AlignMalloc(size_t size) {
#ifdef _MSC_VER
  return (char*)_aligned_malloc(size,
    MV_CONFIG_allocator_alignment);
#else
  void *data;
  CHECK(posix_memalign(&data,
    MV_CONFIG_allocator_alignment, size) == 0);
  return (char*)data;
#endif
}

inline void AlignFree(char *data) {
#ifdef _MSC_VER
  _aligned_free(data);
#else
  free(data);
#endif
}

inline FreeList::FreeList(size_t size) :
size_(size) {
  free_ = new MemoryBlock(size, this);
}

FreeList::~FreeList() {
  MemoryBlock*move = free_, *next;
  while (move) {
    next = move->next;
    delete move;
    move = next;
  }
}

inline char* FreeList::Pop() {
  std::lock_guard<std::mutex> lock(mutex_);
  if (free_ == nullptr) {
    free_ = new MemoryBlock(size_, this);
  }
  char* data = free_->data();
  free_ = free_->next;
  return data;
}

inline void FreeList::Push(MemoryBlock*block) {
  std::lock_guard<std::mutex> lock(mutex_);
  block->next = free_;
  free_ = block;
}

inline MemoryBlock::MemoryBlock(size_t size, FreeList* list) :
next(nullptr), ref_(0) {
  data_ = AlignMalloc(size + header_size_);
  *(FreeList**)(data_) = list;
  *(MemoryBlock**)(data_ + g_pointer_size) = this;
}

MemoryBlock::~MemoryBlock() {
  AlignFree(data_);
}

inline void MemoryBlock::Unlink() {
  if ((--ref_) == 0) {
    (*(FreeList**)data_)->Push(this);
  }
}

inline char* MemoryBlock::data() {
  ++ref_;
  return data_ + header_size_;
}

inline void MemoryBlock::Link() {
  ++ref_;
}

char* SmartAllocator::Alloc(size_t size) {
  if (size <= 32) {
    size = 32;
  }
  else { // 2^n
    size -= 1;
    size |= size >> 32;
    size |= size >> 16;
    size |= size >> 8;
    size |= size >> 4;
    size |= size >> 2;
    size |= size >> 1;
    size += 1;
  }

  {
    std::lock_guard<std::mutex> lock(mutex_);
    if (pools_[size] == nullptr) {
      pools_[size] = new FreeList(size);
    }
  }

  return pools_[size]->Pop();
}

void SmartAllocator::Free(char *data) {
  (*(MemoryBlock**)(data - g_pointer_size))->Unlink();
}

void SmartAllocator::Refer(char *data) {
  (*(MemoryBlock**)(data - g_pointer_size))->Link();
}

SmartAllocator::~SmartAllocator() {
  Log::Debug("~SmartAllocator, final pool size: %d\n", pools_.size());
  for (auto i : pools_) {
    delete i.second;
  }
}

char* Allocator::Alloc(size_t size) {
  char* data = AlignMalloc(size + header_size_);
  // record ref
  *(std::atomic<int>**)data = new std::atomic<int>(1);
  return data + header_size_;
}

void Allocator::Free(char* data) {
  data -= header_size_;
  if (--(**(std::atomic<int>**)data) == 0) {
    delete *(std::atomic<int>**)data;
    AlignFree(data);
  }
}

void Allocator::Refer(char* data) {
  ++(**(std::atomic<int>**)(data - header_size_));
}

MV_DEFINE_string(allocator_type, "smart", "use smart allocator by default");
Allocator* Allocator::Get() {
  if (MV_CONFIG_allocator_type == "smart") {
    static SmartAllocator allocator_;
    return &allocator_;
  }
  static Allocator allocator_;
  return &allocator_;
}

} // namespace multiverso
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <unistd.h>
#include <stx/exception.h>
#include <stx/uri.h>
#include <stx/protobuf/msg.h>
#include <stx/csv/CSVInputStream.h>
#include <common/ConfigDirectory.h>

using namespace stx;

namespace cm {

ConfigDirectory::ConfigDirectory(
    const String& path,
    const InetAddr master_addr) :
    master_addr_(master_addr),
    watcher_running_(false) {
  mdb::MDBOptions mdb_opts;
  mdb_opts.data_filename = "cdb.db",
  mdb_opts.lock_filename = "cdb.db.lck";
  mdb_opts.duplicate_keys = false;

  db_ = mdb::MDB::open(path, mdb_opts);

  listCustomers([this] (const CustomerConfig& cfg) {
    customers_.emplace(cfg.customer(), new CustomerConfigRef(cfg));
  });

  sync();
}

RefPtr<CustomerConfigRef> ConfigDirectory::configFor(
    const String& customer_key) const {
  std::unique_lock<std::mutex> lk(mutex_);

  auto iter = customers_.find(customer_key);
  if (iter == customers_.end()) {
    RAISEF(kNotFoundError, "customer not found: $0", customer_key);
  }

  return iter->second;
}

void ConfigDirectory::listCustomers(
    Function<void (const CustomerConfig& cfg)> fn) const {
  auto prefix = "cfg~";

  Buffer key;
  Buffer value;

  auto txn = db_->startTransaction(true);
  txn->autoAbort();

  auto cursor = txn->getCursor();
  key.append(prefix);

  if (!cursor->getFirstOrGreater(&key, &value)) {
    return;
  }

  do {
    if (!StringUtil::beginsWith(key.toString(), prefix)) {
      break;
    }

    fn(msg::decode<CustomerConfig>(value));
  } while (cursor->getNext(&key, &value));

  cursor->close();
}

void ConfigDirectory::onCustomerConfigChange(
    Function<void (const CustomerConfig& cfg)> fn) {
  std::unique_lock<std::mutex> lk(mutex_);
  on_customer_change_.emplace_back(fn);
}

void ConfigDirectory::addTableDefinition(const TableDefinition& table) {
  std::unique_lock<std::mutex> lk(mutex_);

  if (!StringUtil::isShellSafe(table.table_name())) {
    RAISEF(
        kIllegalArgumentError,
        "invalid table name: '$0'",
        table.table_name());
  }

  if (!table.has_schema_name() && !table.has_schema_inline()) {
    RAISEF(
        kIllegalArgumentError,
        "can't add table without a schema: '$0'",
        table.table_name());
  }

  auto db_key = StringUtil::format(
      "tbl~$0~$1",
      table.customer(),
      table.table_name());

  auto buf = msg::encode(table);

  auto txn = db_->startTransaction(false);
  txn->autoAbort();

  txn->insert(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->commit();

  for (const auto& cb : on_table_change_) {
    cb(table);
  }
}

void ConfigDirectory::updateTableDefinition(const TableDefinition& table) {
  std::unique_lock<std::mutex> lk(mutex_);

  if (!StringUtil::isShellSafe(table.table_name())) {
    RAISEF(
        kIllegalArgumentError,
        "invalid table name: '$0'",
        table.table_name());
  }

  if (!table.has_schema_name() && !table.has_schema_inline()) {
    RAISEF(
        kIllegalArgumentError,
        "can't add table without a schema: '$0'",
        table.table_name());
  }

  auto db_key = StringUtil::format(
      "tbl~$0~$1",
      table.customer(),
      table.table_name());

  auto buf = msg::encode(table);

  auto txn = db_->startTransaction(false);
  txn->autoAbort();

  txn->update(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->commit();

  for (const auto& cb : on_table_change_) {
    cb(table);
  }
}

void ConfigDirectory::listTableDefinitions(
    Function<void (const TableDefinition& table)> fn) const {
  auto prefix = "tbl~";

  Buffer key;
  Buffer value;

  auto txn = db_->startTransaction(true);
  txn->autoAbort();

  auto cursor = txn->getCursor();
  key.append(prefix);

  if (!cursor->getFirstOrGreater(&key, &value)) {
    return;
  }

  do {
    if (!StringUtil::beginsWith(key.toString(), prefix)) {
      break;
    }

    fn(msg::decode<TableDefinition>(value));
  } while (cursor->getNext(&key, &value));

  cursor->close();
}

void ConfigDirectory::onTableDefinitionChange(
    Function<void (const TableDefinition& tbl)> fn) {
  std::unique_lock<std::mutex> lk(mutex_);
  on_table_change_.emplace_back(fn);
}

void ConfigDirectory::sync() {
  auto master_heads = fetchMasterHeads();

  Set<String> needs_update;
  {
    auto txn = db_->startTransaction(true);
    txn->autoAbort();

    for (const auto& head : master_heads) {
      auto db_key = StringUtil::format("head~$0", head.first);
      auto vstr = StringUtil::toString(head.second);

      auto lastver = txn->get(db_key);
      if (lastver.isEmpty() || lastver.get().toString() != vstr) {
        needs_update.emplace(head.first);
      }
    }

    txn->abort();
  }

  for (const auto& obj : needs_update) {
    syncObject(obj);
  }
}

void ConfigDirectory::syncObject(const String& obj) {
  logDebug("analyticsd", "Syncing config object '$0' from master", obj);

  static const String kCustomerPrefix = "customers/";
  if (StringUtil::beginsWith(obj, kCustomerPrefix)) {
    syncCustomerConfig(obj.substr(kCustomerPrefix.size()));
  }
}

void ConfigDirectory::syncCustomerConfig(const String& customer) {
  auto uri = URI(
      StringUtil::format(
          "http://$0/analytics/master/customer_config?customer=$1",
          master_addr_.hostAndPort(),
          URI::urlEncode(customer)));

  http::HTTPClient http;
  auto res = http.executeRequest(http::HTTPRequest::mkGet(uri));
  if (res.statusCode() != 200) {
    RAISEF(kRuntimeError, "error: $0", res.body().toString());
  }

  commitCustomerConfig(msg::decode<CustomerConfig>(res.body()));
}

void ConfigDirectory::commitCustomerConfig(const CustomerConfig& config) {
  auto db_key = StringUtil::format("cfg~$0", config.customer());
  auto hkey = StringUtil::format("head~customers/$0", config.customer());
  auto buf = msg::encode(config);
  auto vstr = StringUtil::toString(config.version());

  std::unique_lock<std::mutex> lk(mutex_);
  auto txn = db_->startTransaction(false);
  txn->autoAbort();
  txn->update(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->update(hkey.data(), hkey.size(), vstr.data(), vstr.size());
  txn->commit();

  customers_.emplace(config.customer(), new CustomerConfigRef(config));

  for (const auto& cb : on_customer_change_) {
    cb(config);
  }
}

HashMap<String, uint64_t> ConfigDirectory::fetchMasterHeads() const {
  auto uri = URI(
      StringUtil::format(
          "http://$0/analytics/master/heads",
          master_addr_.hostAndPort()));

  http::HTTPClient http;
  auto res = http.executeRequest(http::HTTPRequest::mkGet(uri));
  if (res.statusCode() != 200) {
    RAISEF(kRuntimeError, "error: $0", res.body().toString());
  }

  DefaultCSVInputStream csv(BufferInputStream::fromBuffer(&res.body()), '=');

  HashMap<String, uint64_t> heads;
  Vector<String> row;
  while (csv.readNextRow(&row)) {
    if (row.size() != 2) {
      RAISE(kRuntimeError, "invalid response");
    }

    heads[row[0]] = std::stoull(row[1]);
  }

  return heads;
}

void ConfigDirectory::startWatcher() {
  watcher_running_ = true;

  watcher_thread_ = std::thread([this] {
    while (watcher_running_.load()) {
      try {
        sync();
      } catch (const StandardException& e) {
        logCritical("analyticsd", e, "error during master sync");
      }

      usleep(500000);
    }
  });
}

void ConfigDirectory::stopWatcher() {
  if (!watcher_running_) {
    return;
  }

  watcher_running_ = false;
  watcher_thread_.join();
}

} // namespace cm
<commit_msg>version check in ConfigDirectory::commitCustomerConfig<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <unistd.h>
#include <stx/exception.h>
#include <stx/uri.h>
#include <stx/protobuf/msg.h>
#include <stx/csv/CSVInputStream.h>
#include <common/ConfigDirectory.h>

using namespace stx;

namespace cm {

ConfigDirectory::ConfigDirectory(
    const String& path,
    const InetAddr master_addr) :
    master_addr_(master_addr),
    watcher_running_(false) {
  mdb::MDBOptions mdb_opts;
  mdb_opts.data_filename = "cdb.db",
  mdb_opts.lock_filename = "cdb.db.lck";
  mdb_opts.duplicate_keys = false;

  db_ = mdb::MDB::open(path, mdb_opts);

  listCustomers([this] (const CustomerConfig& cfg) {
    customers_.emplace(cfg.customer(), new CustomerConfigRef(cfg));
  });

  sync();
}

RefPtr<CustomerConfigRef> ConfigDirectory::configFor(
    const String& customer_key) const {
  std::unique_lock<std::mutex> lk(mutex_);

  auto iter = customers_.find(customer_key);
  if (iter == customers_.end()) {
    RAISEF(kNotFoundError, "customer not found: $0", customer_key);
  }

  return iter->second;
}

void ConfigDirectory::listCustomers(
    Function<void (const CustomerConfig& cfg)> fn) const {
  auto prefix = "cfg~";

  Buffer key;
  Buffer value;

  auto txn = db_->startTransaction(true);
  txn->autoAbort();

  auto cursor = txn->getCursor();
  key.append(prefix);

  if (!cursor->getFirstOrGreater(&key, &value)) {
    return;
  }

  do {
    if (!StringUtil::beginsWith(key.toString(), prefix)) {
      break;
    }

    fn(msg::decode<CustomerConfig>(value));
  } while (cursor->getNext(&key, &value));

  cursor->close();
}

void ConfigDirectory::onCustomerConfigChange(
    Function<void (const CustomerConfig& cfg)> fn) {
  std::unique_lock<std::mutex> lk(mutex_);
  on_customer_change_.emplace_back(fn);
}

void ConfigDirectory::addTableDefinition(const TableDefinition& table) {
  std::unique_lock<std::mutex> lk(mutex_);

  if (!StringUtil::isShellSafe(table.table_name())) {
    RAISEF(
        kIllegalArgumentError,
        "invalid table name: '$0'",
        table.table_name());
  }

  if (!table.has_schema_name() && !table.has_schema_inline()) {
    RAISEF(
        kIllegalArgumentError,
        "can't add table without a schema: '$0'",
        table.table_name());
  }

  auto db_key = StringUtil::format(
      "tbl~$0~$1",
      table.customer(),
      table.table_name());

  auto buf = msg::encode(table);

  auto txn = db_->startTransaction(false);
  txn->autoAbort();

  txn->insert(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->commit();

  for (const auto& cb : on_table_change_) {
    cb(table);
  }
}

void ConfigDirectory::updateTableDefinition(const TableDefinition& table) {
  std::unique_lock<std::mutex> lk(mutex_);

  if (!StringUtil::isShellSafe(table.table_name())) {
    RAISEF(
        kIllegalArgumentError,
        "invalid table name: '$0'",
        table.table_name());
  }

  if (!table.has_schema_name() && !table.has_schema_inline()) {
    RAISEF(
        kIllegalArgumentError,
        "can't add table without a schema: '$0'",
        table.table_name());
  }

  auto db_key = StringUtil::format(
      "tbl~$0~$1",
      table.customer(),
      table.table_name());

  auto buf = msg::encode(table);

  auto txn = db_->startTransaction(false);
  txn->autoAbort();

  txn->update(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->commit();

  for (const auto& cb : on_table_change_) {
    cb(table);
  }
}

void ConfigDirectory::listTableDefinitions(
    Function<void (const TableDefinition& table)> fn) const {
  auto prefix = "tbl~";

  Buffer key;
  Buffer value;

  auto txn = db_->startTransaction(true);
  txn->autoAbort();

  auto cursor = txn->getCursor();
  key.append(prefix);

  if (!cursor->getFirstOrGreater(&key, &value)) {
    return;
  }

  do {
    if (!StringUtil::beginsWith(key.toString(), prefix)) {
      break;
    }

    fn(msg::decode<TableDefinition>(value));
  } while (cursor->getNext(&key, &value));

  cursor->close();
}

void ConfigDirectory::onTableDefinitionChange(
    Function<void (const TableDefinition& tbl)> fn) {
  std::unique_lock<std::mutex> lk(mutex_);
  on_table_change_.emplace_back(fn);
}

void ConfigDirectory::sync() {
  auto master_heads = fetchMasterHeads();

  Set<String> needs_update;
  {
    auto txn = db_->startTransaction(true);
    txn->autoAbort();

    for (const auto& head : master_heads) {
      auto db_key = StringUtil::format("head~$0", head.first);
      auto vstr = StringUtil::toString(head.second);

      auto lastver = txn->get(db_key);
      if (lastver.isEmpty() || lastver.get().toString() != vstr) {
        needs_update.emplace(head.first);
      }
    }

    txn->abort();
  }

  for (const auto& obj : needs_update) {
    syncObject(obj);
  }
}

void ConfigDirectory::syncObject(const String& obj) {
  logDebug("analyticsd", "Syncing config object '$0' from master", obj);

  static const String kCustomerPrefix = "customers/";
  if (StringUtil::beginsWith(obj, kCustomerPrefix)) {
    syncCustomerConfig(obj.substr(kCustomerPrefix.size()));
  }
}

void ConfigDirectory::syncCustomerConfig(const String& customer) {
  auto uri = URI(
      StringUtil::format(
          "http://$0/analytics/master/fetch_customer_config?customer=$1",
          master_addr_.hostAndPort(),
          URI::urlEncode(customer)));

  http::HTTPClient http;
  auto res = http.executeRequest(http::HTTPRequest::mkGet(uri));
  if (res.statusCode() != 200) {
    RAISEF(kRuntimeError, "error: $0", res.body().toString());
  }

  commitCustomerConfig(msg::decode<CustomerConfig>(res.body()));
}

void ConfigDirectory::commitCustomerConfig(const CustomerConfig& config) {
  auto db_key = StringUtil::format("cfg~$0", config.customer());
  auto hkey = StringUtil::format("head~customers/$0", config.customer());
  auto buf = msg::encode(config);
  auto vstr = StringUtil::toString(config.version());

  std::unique_lock<std::mutex> lk(mutex_);
  auto txn = db_->startTransaction(false);

  auto last_version = 0;
  auto last_version_str = txn->get(hkey);
  if (!last_version_str.isEmpty()) {
    last_version = std::stoull(last_version_str.get().toString());
  }

  if (last_version >= config.version()) {
    RAISE(kRuntimeError, "refusing to commit outdated version");
  }

  txn->autoAbort();
  txn->update(db_key.data(), db_key.size(), buf->data(), buf->size());
  txn->update(hkey.data(), hkey.size(), vstr.data(), vstr.size());
  txn->commit();

  customers_.emplace(config.customer(), new CustomerConfigRef(config));

  for (const auto& cb : on_customer_change_) {
    cb(config);
  }
}

HashMap<String, uint64_t> ConfigDirectory::fetchMasterHeads() const {
  auto uri = URI(
      StringUtil::format(
          "http://$0/analytics/master/heads",
          master_addr_.hostAndPort()));

  http::HTTPClient http;
  auto res = http.executeRequest(http::HTTPRequest::mkGet(uri));
  if (res.statusCode() != 200) {
    RAISEF(kRuntimeError, "error: $0", res.body().toString());
  }

  DefaultCSVInputStream csv(BufferInputStream::fromBuffer(&res.body()), '=');

  HashMap<String, uint64_t> heads;
  Vector<String> row;
  while (csv.readNextRow(&row)) {
    if (row.size() != 2) {
      RAISE(kRuntimeError, "invalid response");
    }

    heads[row[0]] = std::stoull(row[1]);
  }

  return heads;
}

void ConfigDirectory::startWatcher() {
  watcher_running_ = true;

  watcher_thread_ = std::thread([this] {
    while (watcher_running_.load()) {
      try {
        sync();
      } catch (const StandardException& e) {
        logCritical("analyticsd", e, "error during master sync");
      }

      usleep(500000);
    }
  });
}

void ConfigDirectory::stopWatcher() {
  if (!watcher_running_) {
    return;
  }

  watcher_running_ = false;
  watcher_thread_.join();
}

} // namespace cm
<|endoftext|>


<commit_before>#include "cppunit/TestSuite.h"
#include "cppunit/TestResult.h"

namespace CppUnit {

/// Deletes all tests in the suite.
void TestSuite::deleteContents ()
{
  for (std::vector<Test *>::iterator it = m_tests.begin ();
       it != m_tests.end ();
       ++it)
    delete *it;
  m_tests.clear();
}

/// Runs the tests and collects their result in a TestResult.
void TestSuite::run (TestResult *result)
{
    for (std::vector<Test *>::iterator it = m_tests.begin ();
            it != m_tests.end ();
            ++it) {
        if (result->shouldStop ())
            break;

        Test *test = *it;
        test->run (result);
    }

}

/// Counts the number of test cases that will be run by this test.
int TestSuite::countTestCases () const
{
    int count = 0;

    for (std::vector<Test * const>::iterator it = m_tests.begin ();
            it != m_tests.end ();
            ++it)
        count += (*it)->countTestCases ();

    return count;

}

/// Default constructor
TestSuite::TestSuite (std::string name)
  : m_name (name)
{
}

/// Destructor
TestSuite::~TestSuite ()
{
  deleteContents ();
}

/// Adds a test to the suite.
void
  TestSuite::addTest (Test *test)
{
  m_tests.push_back (test);
}

/// Returns a string representation of the test suite.
std::string
  TestSuite::toString () const
{
  return "suite " + getName();
}

/// Returns the name of the test suite.
std::string
  TestSuite::getName () const
{
  return m_name;
}

} // namespace CppUnit

<commit_msg>Fix compilation bug on Win32/MSVC++.<commit_after>#include "cppunit/TestSuite.h"
#include "cppunit/TestResult.h"

namespace CppUnit {

/// Deletes all tests in the suite.
void TestSuite::deleteContents ()
{
  for (std::vector<Test *>::iterator it = m_tests.begin ();
       it != m_tests.end ();
       ++it)
    delete *it;
  m_tests.clear();
}

/// Runs the tests and collects their result in a TestResult.
void TestSuite::run (TestResult *result)
{
    for (std::vector<Test *>::iterator it = m_tests.begin ();
            it != m_tests.end ();
            ++it) {
        if (result->shouldStop ())
            break;

        Test *test = *it;
        test->run (result);
    }

}

/// Counts the number of test cases that will be run by this test.
int TestSuite::countTestCases () const
{
    int count = 0;

    for (std::vector<Test *>::const_iterator it = m_tests.begin ();
            it != m_tests.end ();
            ++it)
        count += (*it)->countTestCases ();

    return count;

}

/// Default constructor
TestSuite::TestSuite (std::string name)
  : m_name (name)
{
}

/// Destructor
TestSuite::~TestSuite ()
{
  deleteContents ();
}

/// Adds a test to the suite.
void
  TestSuite::addTest (Test *test)
{
  m_tests.push_back (test);
}

/// Returns a string representation of the test suite.
std::string
  TestSuite::toString () const
{
  return "suite " + getName();
}

/// Returns the name of the test suite.
std::string
  TestSuite::getName () const
{
  return m_name;
}

} // namespace CppUnit

<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
// Author:		Martin Klemsa
//----------------------------------------------------------------------------
#ifndef _ctoolhu_random_generator_included_
#define _ctoolhu_random_generator_included_

#include "engine.hpp"
#include <boost/random/variate_generator.hpp>
#include <boost/random/uniform_smallint.hpp>

#ifdef _DEBUG_RAND
#include <ctoolhu/event/events.h>
#include <ctoolhu/event/firer.hpp>
#include <string>
#endif

namespace Ctoolhu {

	namespace Random {

		//shortcut for the generator template we'll be using
		template <class Distribution>
		using RandomGenerator = boost::variate_generator<Private::RandomEngine &, Distribution>;

		//generator with run-time bounds
		template <
			class Distribution,
			typename Boundary = int
		>
		class Generator : public RandomGenerator<Distribution> {

			typedef RandomGenerator<Distribution> base_type;

		  public:

			//for number generators
			Generator(Boundary lower, Boundary upper)
				: base_type(Private::SingleRandomEngine::Instance(), Distribution(lower, upper)) {}

			//for bool generator
			Generator()
				: base_type(Private::SingleRandomEngine::Instance(), Distribution()) {}

#ifdef _DEBUG_RAND
			result_type operator()()
			{
				auto res = this->base_type::operator()();
				Event::Fire(Event::Message{"random: " + std::to_string(res)});
				return res;
			}
#endif
		};

		//generator with compile-time bounds
		template <
			int LowerBound,
			int UpperBound,
			class Distribution = std::uniform_int_distribution<>
		>
		class StaticGenerator : public RandomGenerator<Distribution> {

		  public:

			StaticGenerator()
				: RandomGenerator<Distribution>(Private::SingleRandomEngine::Instance(), Distribution(LowerBound, UpperBound)) {}
		};

		//expose typical usages of the dynamic generator
		typedef Generator<std::uniform_int_distribution<>>	IntGenerator;
		typedef Generator<boost::uniform_smallint<>>		SmallIntGenerator;
		typedef Generator<std::uniform_real_distribution<float>, float>	FloatGenerator;
		typedef Generator<std::bernoulli_distribution>		BoolGenerator;

	} //ns Random

} //ns Ctoolhu

#endif
<commit_msg>Corrected random generator build with DEBUG_RAND defined<commit_after>//----------------------------------------------------------------------------
// Author:		Martin Klemsa
//----------------------------------------------------------------------------
#ifndef _ctoolhu_random_generator_included_
#define _ctoolhu_random_generator_included_

#include "engine.hpp"
#include <boost/random/variate_generator.hpp>
#include <boost/random/uniform_smallint.hpp>

#ifdef _DEBUG_RAND
#include <ctoolhu/event/events.h>
#include <ctoolhu/event/firer.hpp>
#include <string>
#endif

namespace Ctoolhu {

	namespace Random {

		//shortcut for the generator template we'll be using
		template <class Distribution>
		using RandomGenerator = boost::variate_generator<Private::RandomEngine &, Distribution>;

		//generator with run-time bounds
		template <
			class Distribution,
			typename Boundary = int
		>
		class Generator : public RandomGenerator<Distribution> {

			typedef RandomGenerator<Distribution> base_type;

		  public:

			//for number generators
			Generator(Boundary lower, Boundary upper)
				: base_type(Private::SingleRandomEngine::Instance(), Distribution(lower, upper)) {}

			//for bool generator
			Generator()
				: base_type(Private::SingleRandomEngine::Instance(), Distribution()) {}

#ifdef _DEBUG_RAND
			auto operator()()
			{
				auto res = this->base_type::operator()();
				Event::Fire(Event::Message{"random: " + std::to_string(res)});
				return res;
			}
#endif
		};

		//generator with compile-time bounds
		template <
			int LowerBound,
			int UpperBound,
			class Distribution = std::uniform_int_distribution<>
		>
		class StaticGenerator : public RandomGenerator<Distribution> {

		  public:

			StaticGenerator()
				: RandomGenerator<Distribution>(Private::SingleRandomEngine::Instance(), Distribution(LowerBound, UpperBound)) {}
		};

		//expose typical usages of the dynamic generator
		typedef Generator<std::uniform_int_distribution<>>	IntGenerator;
		typedef Generator<boost::uniform_smallint<>>		SmallIntGenerator;
		typedef Generator<std::uniform_real_distribution<float>, float>	FloatGenerator;
		typedef Generator<std::bernoulli_distribution>		BoolGenerator;

	} //ns Random

} //ns Ctoolhu

#endif
<|endoftext|>


<commit_before>#include "Benchmark.h"
#include "SkPMFloat.h"
#include "SkRandom.h"

struct PMFloatBench : public Benchmark {
    explicit PMFloatBench(bool clamp) : fClamp(clamp) {}

    const char* onGetName() SK_OVERRIDE { return fClamp ? "SkPMFloat_clamp" : "SkPMFloat_get"; }
    bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; }

    void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
        SkRandom rand;
        for (int i = 0; i < loops; i++) {
            SkPMColor c = SkPreMultiplyColor(rand.nextU());
            SkPMFloat pmf;
            pmf.set(c);
            SkPMColor back = fClamp ? pmf.clamped() : pmf.get();
            if (c != back) { SkFAIL("no joy"); }  // This conditional makes this not compile away.
        }
    }

    bool fClamp;
};
DEF_BENCH(return new PMFloatBench( true);)
DEF_BENCH(return new PMFloatBench(false);)
<commit_msg>Trim the fat off SkPMFloat bench.<commit_after>#include "Benchmark.h"
#include "SkPMFloat.h"

// Used to prevent the compiler from optimizing away the whole loop.
volatile uint32_t blackhole = 0;

// Not a great random number generator, but it's very fast.
// The code we're measuring is quite fast, so low overhead is essential.
static uint32_t lcg_rand(uint32_t* seed) {
    *seed *= 1664525;
    *seed += 1013904223;
    return *seed;
}

struct PMFloatBench : public Benchmark {
    explicit PMFloatBench(bool clamp) : fClamp(clamp) {}

    const char* onGetName() SK_OVERRIDE { return fClamp ? "SkPMFloat_clamp" : "SkPMFloat_get"; }
    bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; }

    void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
        // Unlike blackhole, junk can and probably will be a register.
        uint32_t junk = 0;
        uint32_t seed = 0;
        for (int i = 0; i < loops; i++) {
        #ifdef SK_DEBUG
            // Our SkASSERTs will remind us that it's technically required that we premultiply.
            SkPMColor c = SkPreMultiplyColor(lcg_rand(&seed));
        #else
            // But it's a lot faster not to, and this code won't really mind the non-PM colors.
            SkPMColor c = lcg_rand(&seed);
        #endif
            SkPMFloat pmf;
            pmf.set(c);
            SkPMColor back = fClamp ? pmf.clamped() : pmf.get();
            junk ^= back;
        }
        blackhole ^= junk;
    }

    bool fClamp;
};
DEF_BENCH(return new PMFloatBench( true);)
DEF_BENCH(return new PMFloatBench(false);)
<|endoftext|>