<commit_before>#include <vector>
#include <boost/filesystem.hpp>
#include <bitcoin/bitcoin.hpp>
#include <obelisk/zmq_message.hpp>
#include "config.hpp"

#define HEARTBEAT_LIVENESS  3       //  3-5 is reasonable
#define HEARTBEAT_INTERVAL  1000    //  msecs

#define LOG_BALANCER "balancer"

#if ZMQ_VERSION_MAJOR == 4
    constexpr size_t zmq_uuid_size = 5;
#else
    constexpr size_t zmq_uuid_size = 17;
#endif

using namespace bc;
using namespace obelisk;

typedef data_chunk worker_uuid;

static void s_version_assert(int want_major, int want_minor)
{
    int major, minor, patch;
    zmq_version (&major, &minor, &patch);
    if (major < want_major
    || (major == want_major && minor < want_minor)) {
        std::cout << "Current 0MQ version is " << major << "." << minor << std::endl;
        std::cout << "Application needs at least " << want_major << "." << want_minor
              << " - cannot continue" << std::endl;
        exit (EXIT_FAILURE);
    }
}

//  Return current system clock as milliseconds
static int64_t s_clock(void)
{
#if (defined (__WINDOWS__))
    SYSTEMTIME st;
    GetSystemTime (&st);
    return (int64_t) st.wSecond * 1000 + st.wMilliseconds;
#else
    struct timeval tv;
    gettimeofday (&tv, NULL);
    return (int64_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000);
#endif
}

//  This defines one active worker in our worker queue

typedef struct {
    worker_uuid identity;           //  Address of worker
    int64_t     expiry;             //  Expires at this time
} worker_t;

//  Insert worker at end of queue, reset expiry
//  Worker must not already be in queue
void s_worker_append(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            std::cout << "E: duplicate worker identity " << identity << std::endl;
            found = true;
            break;
        }
    }
    if (!found)
    {
        worker_t worker;
        worker.identity = identity;
        worker.expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
        queue.push_back(worker);
    }
}

//  Remove worker from queue, if present
void s_worker_delete(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            it = queue.erase(it);
            break;
        }
    }
}

//  Reset worker expiry, worker must be present
void s_worker_refresh(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
           it->expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
           found = true;
           break;
        }
    }
    if (!found)
    {
       std::cout << "E: worker " << identity << " not ready" << std::endl;
    }
}

//  Pop next available worker off queue, return identity
const worker_uuid s_worker_dequeue(std::vector<worker_t>& queue)
{
    assert(queue.size());
    const worker_uuid identity = queue[0].identity;
    queue.erase(queue.begin());
    return identity;
}

//  Look for & kill expired workers
void s_queue_purge(std::vector<worker_t>& queue)
{
    int64_t clock = s_clock();
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (clock > it->expiry)
        {
           it = queue.erase(it) - 1;
        }
    }
}

typedef std::vector<worker_t> worker_queue;

void forward_request(zmq::socket_t& frontend, zmq::socket_t& backend,
    worker_queue& queue)
{
    // Get client request.
    zmq_message msg_in;
    msg_in.recv(frontend);
    const data_stack& in_parts = msg_in.parts();

    if (in_parts.size() != 6)
    {
        log_warning(LOG_BALANCER) << "Wrong sized message";
        return;
    }
    // First item is client's identity.
    if (in_parts[0].size() != zmq_uuid_size)
    {
        log_warning(LOG_BALANCER) << "Client UUID malformed " << in_parts[0];
        return;
    }
    // Second item is worker identity or nothing.
    if (in_parts[1].size() > 255)
    {
        log_warning(LOG_BALANCER) << "Worker UUID malformed";
        return;
    }

    // We now deconstruct the request message to the backend
    // which looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // And create a new message that looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // Before sending it to the worker.

    // This is so the client can specify a worker to send their
    // request specifically to.

    zmq_message msg_out;
    // If second frame is nothing, then we select a random worker.
    if (in_parts[1].empty())
    {
        // Route to next worker
        worker_uuid worker_identity = s_worker_dequeue(queue);
        msg_out.append(worker_identity);
    }
    else
    {
        // Route to client's preferred worker.
        msg_out.append(in_parts[1]);
    }
    msg_out.append(in_parts[0]);
    // Copy the remaining data.
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    msg_out.send(backend);
}

void handle_control_message(const data_stack& in_parts,
    worker_queue& queue, const worker_uuid& identity)
{
    std::string command(in_parts[1].begin(), in_parts[1].end());
    log_info(LOG_BALANCER) << "command: " << command;
    if (command == "READY")
    {
        s_worker_delete(queue, identity);
        s_worker_append(queue, identity);
    }
    else if (command == "HEARTBEAT")
    {
        s_worker_refresh(queue, identity);
    }
    else
        log_error(LOG_BALANCER)
            << "Invalid command from " << identity;
}

void passback_response(zmq::socket_t& backend, zmq::socket_t& frontend,
    worker_queue& queue)
{
    zmq_message msg_in;
    msg_in.recv(backend);
    const data_stack& in_parts = msg_in.parts();
    BITCOIN_ASSERT(in_parts.size() == 2 || in_parts.size() == 6);
    worker_uuid identity = in_parts[0];

    // Return reply to client if it's not a control message
    if (in_parts.size() == 2)
        return handle_control_message(in_parts, queue, identity);

    // We now deconstruct the request message to the frontend
    // which looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // And create a new message that looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // Before sending it to the backend.

    // This is so the client will know which worker
    // responded to their request.

    BITCOIN_ASSERT(in_parts.size() == 6);
    zmq_message msg_out;
    BITCOIN_ASSERT(in_parts[1].size() == zmq_uuid_size);
    msg_out.append(in_parts[1]);
    BITCOIN_ASSERT(in_parts[0].size() > 0 && in_parts[0].size() < 256);
    msg_out.append(in_parts[0]);
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    BITCOIN_ASSERT(in_parts.size() == msg_out.parts().size());
    msg_out.send(frontend);
    // Add worker back to available pool of workers.
    s_worker_append(queue, identity);
}

int main(int argc, char** argv)
{
    s_version_assert(2, 1);
    config_map_type config;
    if (argc == 2)
    {
        std::cout << "Using config file: " << argv[1] << std::endl;
        load_config(config, argv[1]);
    }
    else
    {
        using boost::filesystem::path;
        path conf_filename = path(SYSCONFDIR) / "obelisk" / "balancer.cfg";
        load_config(config, conf_filename.native());
    }

    // Prepare our context and sockets
    zmq::context_t context(1);
    zmq::socket_t frontend(context, ZMQ_ROUTER);
    zmq::socket_t backend(context, ZMQ_ROUTER);
    // For clients
    frontend.bind(config["frontend"].c_str());
    // For workers
    backend.bind(config["backend"].c_str());

    // Queue of available workers
    worker_queue queue;
    // Send out heartbeats at regular intervals
    int64_t heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;

    while (1)
    {
        zmq::pollitem_t items[] = {
            { backend,  0, ZMQ_POLLIN, 0 },
            { frontend, 0, ZMQ_POLLIN, 0 }
        };

        // Poll frontend only if we have available workers
        if (queue.empty())
            zmq::poll(items, 1, HEARTBEAT_INTERVAL * 1000);
        else
            zmq::poll(items, 2, HEARTBEAT_INTERVAL * 1000);

        // Handle worker activity on backend
        if (items [0].revents & ZMQ_POLLIN)
            passback_response(backend, frontend, queue);
        if (items [1].revents & ZMQ_POLLIN)
            forward_request(frontend, backend, queue);

        //  Send heartbeats to idle workers if it's time
        if (s_clock() > heartbeat_at)
        {
            for (auto it = queue.begin(); it < queue.end(); ++it)
            {
                zmq_message msg;
                msg.append(it->identity);
                std::string command = "HEARTBEAT";
                msg.append(data_chunk(command.begin(), command.end()));
                msg.send(backend);
            }
            heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;
        }
        s_queue_purge(queue);
    }
    //  We never exit the main loop
    //  But pretend to do the right shutdown anyhow
    queue.clear();
    return 0;
}

<commit_msg>remove redundant info output about which config file is loaded.<commit_after>#include <vector>
#include <boost/filesystem.hpp>
#include <bitcoin/bitcoin.hpp>
#include <obelisk/zmq_message.hpp>
#include "config.hpp"

#define HEARTBEAT_LIVENESS  3       //  3-5 is reasonable
#define HEARTBEAT_INTERVAL  1000    //  msecs

#define LOG_BALANCER "balancer"

#if ZMQ_VERSION_MAJOR == 4
    constexpr size_t zmq_uuid_size = 5;
#else
    constexpr size_t zmq_uuid_size = 17;
#endif

using namespace bc;
using namespace obelisk;

typedef data_chunk worker_uuid;

static void s_version_assert(int want_major, int want_minor)
{
    int major, minor, patch;
    zmq_version (&major, &minor, &patch);
    if (major < want_major
    || (major == want_major && minor < want_minor)) {
        std::cout << "Current 0MQ version is " << major << "." << minor << std::endl;
        std::cout << "Application needs at least " << want_major << "." << want_minor
              << " - cannot continue" << std::endl;
        exit (EXIT_FAILURE);
    }
}

//  Return current system clock as milliseconds
static int64_t s_clock(void)
{
#if (defined (__WINDOWS__))
    SYSTEMTIME st;
    GetSystemTime (&st);
    return (int64_t) st.wSecond * 1000 + st.wMilliseconds;
#else
    struct timeval tv;
    gettimeofday (&tv, NULL);
    return (int64_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000);
#endif
}

//  This defines one active worker in our worker queue

typedef struct {
    worker_uuid identity;           //  Address of worker
    int64_t     expiry;             //  Expires at this time
} worker_t;

//  Insert worker at end of queue, reset expiry
//  Worker must not already be in queue
void s_worker_append(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            std::cout << "E: duplicate worker identity " << identity << std::endl;
            found = true;
            break;
        }
    }
    if (!found)
    {
        worker_t worker;
        worker.identity = identity;
        worker.expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
        queue.push_back(worker);
    }
}

//  Remove worker from queue, if present
void s_worker_delete(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            it = queue.erase(it);
            break;
        }
    }
}

//  Reset worker expiry, worker must be present
void s_worker_refresh(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
           it->expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
           found = true;
           break;
        }
    }
    if (!found)
    {
       std::cout << "E: worker " << identity << " not ready" << std::endl;
    }
}

//  Pop next available worker off queue, return identity
const worker_uuid s_worker_dequeue(std::vector<worker_t>& queue)
{
    assert(queue.size());
    const worker_uuid identity = queue[0].identity;
    queue.erase(queue.begin());
    return identity;
}

//  Look for & kill expired workers
void s_queue_purge(std::vector<worker_t>& queue)
{
    int64_t clock = s_clock();
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (clock > it->expiry)
        {
           it = queue.erase(it) - 1;
        }
    }
}

typedef std::vector<worker_t> worker_queue;

void forward_request(zmq::socket_t& frontend, zmq::socket_t& backend,
    worker_queue& queue)
{
    // Get client request.
    zmq_message msg_in;
    msg_in.recv(frontend);
    const data_stack& in_parts = msg_in.parts();

    if (in_parts.size() != 6)
    {
        log_warning(LOG_BALANCER) << "Wrong sized message";
        return;
    }
    // First item is client's identity.
    if (in_parts[0].size() != zmq_uuid_size)
    {
        log_warning(LOG_BALANCER) << "Client UUID malformed " << in_parts[0];
        return;
    }
    // Second item is worker identity or nothing.
    if (in_parts[1].size() > 255)
    {
        log_warning(LOG_BALANCER) << "Worker UUID malformed";
        return;
    }

    // We now deconstruct the request message to the backend
    // which looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // And create a new message that looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // Before sending it to the worker.

    // This is so the client can specify a worker to send their
    // request specifically to.

    zmq_message msg_out;
    // If second frame is nothing, then we select a random worker.
    if (in_parts[1].empty())
    {
        // Route to next worker
        worker_uuid worker_identity = s_worker_dequeue(queue);
        msg_out.append(worker_identity);
    }
    else
    {
        // Route to client's preferred worker.
        msg_out.append(in_parts[1]);
    }
    msg_out.append(in_parts[0]);
    // Copy the remaining data.
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    msg_out.send(backend);
}

void handle_control_message(const data_stack& in_parts,
    worker_queue& queue, const worker_uuid& identity)
{
    std::string command(in_parts[1].begin(), in_parts[1].end());
    log_info(LOG_BALANCER) << "command: " << command;
    if (command == "READY")
    {
        s_worker_delete(queue, identity);
        s_worker_append(queue, identity);
    }
    else if (command == "HEARTBEAT")
    {
        s_worker_refresh(queue, identity);
    }
    else
        log_error(LOG_BALANCER)
            << "Invalid command from " << identity;
}

void passback_response(zmq::socket_t& backend, zmq::socket_t& frontend,
    worker_queue& queue)
{
    zmq_message msg_in;
    msg_in.recv(backend);
    const data_stack& in_parts = msg_in.parts();
    BITCOIN_ASSERT(in_parts.size() == 2 || in_parts.size() == 6);
    worker_uuid identity = in_parts[0];

    // Return reply to client if it's not a control message
    if (in_parts.size() == 2)
        return handle_control_message(in_parts, queue, identity);

    // We now deconstruct the request message to the frontend
    // which looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // And create a new message that looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // Before sending it to the backend.

    // This is so the client will know which worker
    // responded to their request.

    BITCOIN_ASSERT(in_parts.size() == 6);
    zmq_message msg_out;
    BITCOIN_ASSERT(in_parts[1].size() == zmq_uuid_size);
    msg_out.append(in_parts[1]);
    BITCOIN_ASSERT(in_parts[0].size() > 0 && in_parts[0].size() < 256);
    msg_out.append(in_parts[0]);
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    BITCOIN_ASSERT(in_parts.size() == msg_out.parts().size());
    msg_out.send(frontend);
    // Add worker back to available pool of workers.
    s_worker_append(queue, identity);
}

int main(int argc, char** argv)
{
    s_version_assert(2, 1);
    config_map_type config;
    if (argc == 2)
        load_config(config, argv[1]);
    else
    {
        using boost::filesystem::path;
        path conf_filename = path(SYSCONFDIR) / "obelisk" / "balancer.cfg";
        load_config(config, conf_filename.native());
    }

    // Prepare our context and sockets
    zmq::context_t context(1);
    zmq::socket_t frontend(context, ZMQ_ROUTER);
    zmq::socket_t backend(context, ZMQ_ROUTER);
    // For clients
    frontend.bind(config["frontend"].c_str());
    // For workers
    backend.bind(config["backend"].c_str());

    // Queue of available workers
    worker_queue queue;
    // Send out heartbeats at regular intervals
    int64_t heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;

    while (1)
    {
        zmq::pollitem_t items[] = {
            { backend,  0, ZMQ_POLLIN, 0 },
            { frontend, 0, ZMQ_POLLIN, 0 }
        };

        // Poll frontend only if we have available workers
        if (queue.empty())
            zmq::poll(items, 1, HEARTBEAT_INTERVAL * 1000);
        else
            zmq::poll(items, 2, HEARTBEAT_INTERVAL * 1000);

        // Handle worker activity on backend
        if (items [0].revents & ZMQ_POLLIN)
            passback_response(backend, frontend, queue);
        if (items [1].revents & ZMQ_POLLIN)
            forward_request(frontend, backend, queue);

        //  Send heartbeats to idle workers if it's time
        if (s_clock() > heartbeat_at)
        {
            for (auto it = queue.begin(); it < queue.end(); ++it)
            {
                zmq_message msg;
                msg.append(it->identity);
                std::string command = "HEARTBEAT";
                msg.append(data_chunk(command.begin(), command.end()));
                msg.send(backend);
            }
            heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;
        }
        s_queue_purge(queue);
    }
    //  We never exit the main loop
    //  But pretend to do the right shutdown anyhow
    queue.clear();
    return 0;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef RULE_HPP
#define RULE_HPP
// stl
#include <string>
#include <vector>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
// mapnik
#include <mapnik/line_symbolizer.hpp>
#include <mapnik/line_pattern_symbolizer.hpp>
#include <mapnik/polygon_symbolizer.hpp>
#include <mapnik/polygon_pattern_symbolizer.hpp>
#include <mapnik/point_symbolizer.hpp>
#include <mapnik/raster_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/filter.hpp>
#include <mapnik/filter_visitor.hpp>

namespace mapnik
{
    inline bool operator==(point_symbolizer const& lhs,
                           point_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }
    inline bool operator==(line_symbolizer const& lhs,
                           line_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }
    inline bool operator==(line_pattern_symbolizer const& lhs,
                           line_pattern_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(polygon_symbolizer const& lhs,
                           polygon_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(polygon_pattern_symbolizer const& lhs,
                           polygon_pattern_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(raster_symbolizer const& lhs,
                           raster_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(text_symbolizer const& lhs,
                           text_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(shield_symbolizer const& lhs,
                           shield_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    typedef boost::variant<point_symbolizer,
                           line_symbolizer,
                           line_pattern_symbolizer,
                           polygon_symbolizer,
                           polygon_pattern_symbolizer,
                           raster_symbolizer,
                           shield_symbolizer,
                           text_symbolizer> symbolizer;

    typedef std::vector<symbolizer> symbolizers;

    template <typename FeatureT> class all_filter;

    template <typename FeatureT,template <typename> class Filter>
    class rule
    {
        typedef Filter<FeatureT> filter_type;
        typedef boost::shared_ptr<filter_type> filter_ptr;
    private:

        std::string name_;
        std::string title_;
        std::string abstract_;
        double min_scale_;
        double max_scale_;
        symbolizers syms_;
        filter_ptr filter_;
        bool else_filter_;
    public:
        rule()
            : name_(),
              title_(),
              abstract_(),
              min_scale_(0),
              max_scale_(std::numeric_limits<double>::infinity()),
              syms_(),
              filter_(new all_filter<FeatureT>),
              else_filter_(false) {}

        rule(const std::string& name,
             const std::string& title="",
             double min_scale_denominator=0,
             double max_scale_denominator=std::numeric_limits<double>::infinity())
            : name_(name),
              title_(title),
              min_scale_(min_scale_denominator),
              max_scale_(max_scale_denominator),
              syms_(),
              filter_(new all_filter<FeatureT>),
              else_filter_(false) {}

        rule(const rule& rhs)
            : name_(rhs.name_),
              title_(rhs.title_),
              abstract_(rhs.abstract_),
              min_scale_(rhs.min_scale_),
              max_scale_(rhs.max_scale_),
              syms_(rhs.syms_),
              filter_(rhs.filter_),
              else_filter_(rhs.else_filter_) {}

        rule& operator=(rule const& rhs)
        {
            rule tmp(rhs);
            swap(tmp);
            return *this;
        }
        bool operator==(rule const& other)
        {
            return  (this == &other);
        }

        void set_max_scale(double scale)
        {
            max_scale_=scale;
        }

        double get_max_scale() const
        {
            return max_scale_;
        }

        void set_min_scale(double scale)
        {
            min_scale_=scale;
        }

        double get_min_scale() const
        {
            return min_scale_;
        }

        void set_name(std::string const& name)
        {
            name_=name;
        }

        std::string const& get_name() const
        {
            return name_;
        }

        std::string const& get_title() const
        {
            return  title_;
        }

        void set_title(std::string const& title)
        {
            title_=title;
        }

        void set_abstract(std::string const& abstract)
        {
            abstract_=abstract;
        }

        std::string const& get_abstract() const
        {
            return abstract_;
        }

        void append(const symbolizer& sym)
        {
            syms_.push_back(sym);
        }

        void remove_at(size_t index)
        {
            if (index < syms_.size())
            {
                syms_.erase(syms_.begin()+index);
            }
        }

        const symbolizers& get_symbolizers() const
        {
            return syms_;
        }

        symbolizers::const_iterator begin()
        {
            return syms_.begin();
        }

        symbolizers::const_iterator end()
        {
            return syms_.end();
        }

        void set_filter(const filter_ptr& filter)
        {
            filter_=filter;
        }

        filter_ptr const& get_filter() const
        {
            return filter_;
        }

        void set_else(bool else_filter)
        {
            else_filter_=else_filter;
        }

        bool has_else_filter() const
        {
            return else_filter_;
        }

        bool active(double scale) const
        {
            return ( scale > min_scale_ && scale < max_scale_ );
        }

        void accept(filter_visitor<FeatureT>& v) const
        {
            v.visit(*this);
        }

    private:

        void swap(rule& rhs) throw()
        {
            name_=rhs.name_;
            title_=rhs.title_;
            abstract_=rhs.abstract_;
            min_scale_=rhs.min_scale_;
            max_scale_=rhs.max_scale_;
            syms_=rhs.syms_;
            filter_=rhs.filter_;
            else_filter_=rhs.else_filter_;
        }
    };

    typedef rule<Feature,filter> rule_type;
}

#endif //RULE_HPP
<commit_msg>fixed scale_denominator  <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef RULE_HPP
#define RULE_HPP
// stl
#include <string>
#include <vector>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
// mapnik
#include <mapnik/line_symbolizer.hpp>
#include <mapnik/line_pattern_symbolizer.hpp>
#include <mapnik/polygon_symbolizer.hpp>
#include <mapnik/polygon_pattern_symbolizer.hpp>
#include <mapnik/point_symbolizer.hpp>
#include <mapnik/raster_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/filter.hpp>
#include <mapnik/filter_visitor.hpp>

namespace mapnik
{
    inline bool operator==(point_symbolizer const& lhs,
                           point_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }
    inline bool operator==(line_symbolizer const& lhs,
                           line_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }
    inline bool operator==(line_pattern_symbolizer const& lhs,
                           line_pattern_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(polygon_symbolizer const& lhs,
                           polygon_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(polygon_pattern_symbolizer const& lhs,
                           polygon_pattern_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(raster_symbolizer const& lhs,
                           raster_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(text_symbolizer const& lhs,
                           text_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    inline bool operator==(shield_symbolizer const& lhs,
                           shield_symbolizer const& rhs)
    {
        return (&lhs == &rhs);
    }

    typedef boost::variant<point_symbolizer,
                           line_symbolizer,
                           line_pattern_symbolizer,
                           polygon_symbolizer,
                           polygon_pattern_symbolizer,
                           raster_symbolizer,
                           shield_symbolizer,
                           text_symbolizer> symbolizer;

    typedef std::vector<symbolizer> symbolizers;

    template <typename FeatureT> class all_filter;

    template <typename FeatureT,template <typename> class Filter>
    class rule
    {
        typedef Filter<FeatureT> filter_type;
        typedef boost::shared_ptr<filter_type> filter_ptr;
    private:

        std::string name_;
        std::string title_;
        std::string abstract_;
        double min_scale_;
        double max_scale_;
        symbolizers syms_;
        filter_ptr filter_;
        bool else_filter_;
    public:
        rule()
            : name_(),
              title_(),
              abstract_(),
              min_scale_(0),
              max_scale_(std::numeric_limits<double>::infinity()),
              syms_(),
              filter_(new all_filter<FeatureT>),
              else_filter_(false) {}

        rule(const std::string& name,
             const std::string& title="",
             double min_scale_denominator=0,
             double max_scale_denominator=std::numeric_limits<double>::infinity())
            : name_(name),
              title_(title),
              min_scale_(min_scale_denominator),
              max_scale_(max_scale_denominator),
              syms_(),
              filter_(new all_filter<FeatureT>),
              else_filter_(false) {}

        rule(const rule& rhs)
            : name_(rhs.name_),
              title_(rhs.title_),
              abstract_(rhs.abstract_),
              min_scale_(rhs.min_scale_),
              max_scale_(rhs.max_scale_),
              syms_(rhs.syms_),
              filter_(rhs.filter_),
              else_filter_(rhs.else_filter_) {}

        rule& operator=(rule const& rhs)
        {
            rule tmp(rhs);
            swap(tmp);
            return *this;
        }
        bool operator==(rule const& other)
        {
            return  (this == &other);
        }

        void set_max_scale(double scale)
        {
            max_scale_=scale;
        }

        double get_max_scale() const
        {
            return max_scale_;
        }

        void set_min_scale(double scale)
        {
            min_scale_=scale;
        }

        double get_min_scale() const
        {
            return min_scale_;
        }

        void set_name(std::string const& name)
        {
            name_=name;
        }

        std::string const& get_name() const
        {
            return name_;
        }

        std::string const& get_title() const
        {
            return  title_;
        }

        void set_title(std::string const& title)
        {
            title_=title;
        }

        void set_abstract(std::string const& abstract)
        {
            abstract_=abstract;
        }

        std::string const& get_abstract() const
        {
            return abstract_;
        }

        void append(const symbolizer& sym)
        {
            syms_.push_back(sym);
        }

        void remove_at(size_t index)
        {
            if (index < syms_.size())
            {
                syms_.erase(syms_.begin()+index);
            }
        }

        const symbolizers& get_symbolizers() const
        {
            return syms_;
        }

        symbolizers::const_iterator begin()
        {
            return syms_.begin();
        }

        symbolizers::const_iterator end()
        {
            return syms_.end();
        }

        void set_filter(const filter_ptr& filter)
        {
            filter_=filter;
        }

        filter_ptr const& get_filter() const
        {
            return filter_;
        }

        void set_else(bool else_filter)
        {
            else_filter_=else_filter;
        }

        bool has_else_filter() const
        {
            return else_filter_;
        }

        bool active(double scale) const
        {
            return ( scale >= min_scale_ - 1e-6 && scale < max_scale_ + 1e-6);
        }

        void accept(filter_visitor<FeatureT>& v) const
        {
            v.visit(*this);
        }

    private:

        void swap(rule& rhs) throw()
        {
            name_=rhs.name_;
            title_=rhs.title_;
            abstract_=rhs.abstract_;
            min_scale_=rhs.min_scale_;
            max_scale_=rhs.max_scale_;
            syms_=rhs.syms_;
            filter_=rhs.filter_;
            else_filter_=rhs.else_filter_;
        }
    };

    typedef rule<Feature,filter> rule_type;
}

#endif //RULE_HPP
<|endoftext|>


<commit_before>#include <simcode/log/logging.h>

using namespace simcode;
using namespace log;

static const char* LogLevelName[]={
    "[TRACE]",
    "[DEBUG]",
    "[INFO]",
    "[WARN]",
    "[ERROR]",
    "[FATAL]"
};

static const char* get_level_name(int level)
{
    return LogLevelName[level];
}

int Logging::Init(const std::string& filename, uint64_t rotate_size)
{
    int ret;
    ret = logFile_.open(filename, rotate_size);
    if (0 != ret) return ret;
}

void Logging::log_out(int level,
                 const char* filename,
                 int linenum,
                 const char* funcname,
                 const char* msg)
{
    char data[LogFile::LOG_BUF_LEN];
    char buf[LogFile::LOG_BUF_LEN];
    int len;
    len = snprintf(data, sizeof(data), "%s|%d|%s|%s",
             filename, linenum, funcname, msg);
    len = logFile_.logData(data, len,
                           get_level_name(level), buf);
    {
    ScopeLock lock(mutex_);
    logFile_.logWrite(buf, len);
    }
}

int GlobalLogging::Init(const std::string& name, uint64_t rotate_size, int level)
{
    simcode::GlobalLogger::set_level(level);
    Logging* logging = new Logging;
    if (0 != logging->Init(name, rotate_size))
    {
        delete logging;
        return 1;
    }
    simcode::GlobalLogger::set_base_logger(logging);
    return 0;
}

<commit_msg>mod get_level_name<commit_after>#include <simcode/log/logging.h>

using namespace simcode;
using namespace log;

static const char* LogLevelName[]={
    "[TRACE]",
    "[DEBUG]",
    "[INFO]",
    "[WARN]",
    "[ERROR]",
    "[FATAL]"
};

static const char* get_level_name(int level)
{
    return LogLevelName[level-1];
}

int Logging::Init(const std::string& filename, uint64_t rotate_size)
{
    int ret;
    ret = logFile_.open(filename, rotate_size);
    if (0 != ret) return ret;
}

void Logging::log_out(int level,
                 const char* filename,
                 int linenum,
                 const char* funcname,
                 const char* msg)
{
    char data[LogFile::LOG_BUF_LEN];
    char buf[LogFile::LOG_BUF_LEN];
    int len;
    len = snprintf(data, sizeof(data), "%s|%d|%s|%s",
             filename, linenum, funcname, msg);
    len = logFile_.logData(data, len,
                           get_level_name(level), buf);
    {
    ScopeLock lock(mutex_);
    logFile_.logWrite(buf, len);
    }
}

int GlobalLogging::Init(const std::string& name, uint64_t rotate_size, int level)
{
    simcode::GlobalLogger::set_level(level);
    Logging* logging = new Logging;
    if (0 != logging->Init(name, rotate_size))
    {
        delete logging;
        return 1;
    }
    simcode::GlobalLogger::set_base_logger(logging);
    return 0;
}

<|endoftext|>


<commit_before>/******************************************************************************
 * $Id$
 *
 * Project:  pdal - http://pdal.org - A BSD library for LAS format data.
 * Purpose:  LAS bounds class
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Martin Isenburg or Iowa Department
 *       of Natural Resources nor the names of its contributors may be
 *       used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef INCLUDED_BOUNDS_HPP
#define INCLUDED_BOUNDS_HPP

#include <pdal/pdal_internal.hpp>

#include <cassert>
#include <vector>
#include <sstream>
#include <boost/property_tree/ptree.hpp>

#include <pdal/Vector.hpp>
#include <pdal/Range.hpp>

namespace pdal
{

/// Bounds is for manipulating n-dimensional ranges of data.  Typically
/// used for defining the spatial extents of XYZ data, this class can also be
/// used for defining bounds of other dimensions.
template <typename T>
class PDAL_DLL Bounds
{
public:
    typedef typename std::vector< Range<T> > RangeVector;

private:
    RangeVector m_ranges;

public:

/** @name Constructors
*/

    /// Constructs an empty Bounds instance
    /// with no dimensions
    Bounds<T>()
    {
        m_ranges.resize(0);
    }

    /// Copy constructor
    Bounds(Bounds const& other)
        : m_ranges(other.m_ranges)
    {
    }

    /// Constructs a Bounds instance from a vector
    /// of Range
    Bounds(RangeVector const& ranges)
        :
        m_ranges(ranges)
    {
    }

    /// Convenience constructor for typical 3D case
    Bounds( T minx,
            T miny,
            T minz,
            T maxx,
            T maxy,
            T maxz)
    {
        m_ranges.resize(3);

        m_ranges[0].setMinimum(minx);
        m_ranges[1].setMinimum(miny);
        m_ranges[2].setMinimum(minz);

        m_ranges[0].setMaximum(maxx);
        m_ranges[1].setMaximum(maxy);
        m_ranges[2].setMaximum(maxz);

        assert(verify());

    }

    /// Convenience constructor for typical 2D case
    Bounds( T minx,
            T miny,
            T maxx,
            T maxy)
    {

        m_ranges.resize(2);

        m_ranges[0].setMinimum(minx);
        m_ranges[1].setMinimum(miny);

        m_ranges[0].setMaximum(maxx);
        m_ranges[1].setMaximum(maxy);

        assert(verify());
    }

    /// Convenience constructor for Vector of minimum and maximum
    /// values.
    Bounds(const Vector<T>& minimum, const Vector<T>& maximum)
    {
        assert(minimum.size() == maximum.size());

        m_ranges.resize(minimum.size());

        for (std::size_t i=0; i<minimum.size(); i++)
        {
            m_ranges[i].setMinimum(minimum[i]);
            m_ranges[i].setMaximum(maximum[i]);
        }

        assert(verify());
    }

/** @name Data manipulation
*/

    T getMinimum(std::size_t const& index) const
    {
        if (m_ranges.size() <= index)
        {
            // std::ostringstream msg;
            // msg << "Bounds dimensions, " << ranges.size() <<", is less "
            //     << "than the given index, " << index;
            // throw pdal::bounds_error(msg.str());
            return 0;
        }
        return m_ranges[index].getMinimum();
    }

    void setMinimum(std::size_t const& index, T v)
    {
        if (m_ranges.size() <= index)
        {
            m_ranges.resize(index + 1);
        }
        m_ranges[index].setMinimum(v);
    }

    T getMaximum(std::size_t const& index) const
    {
        if (m_ranges.size() <= index)
        {
            // std::ostringstream msg;
            // msg << "Bounds dimensions, " << m_ranges.size() <<", is less "
            //     << "than the given index, " << index;
            // throw pdal::bounds_error(msg.str());
            return 0;
        }
        return m_ranges[index].getMaximum();
    }

    void setMaximum(std::size_t const& index, T v)
    {
        if (m_ranges.size() <= index)
        {
            m_ranges.resize(index + 1);
        }
        m_ranges[index].setMaximum(v);
    }

    Vector<T> getMinimum()
    {
        std::vector<T> vec;

        for (std::size_t i=0; i<m_ranges.size(); i++)
        {
            vec.push_back(m_ranges[i].getMinimum());
        }

        return Vector<T>(vec);
    }

    Vector<T> getMaximum()
    {
        std::vector<T> vec;

        for (std::size_t i=0; i<m_ranges.size(); i++)
        {
            vec.push_back(m_ranges[i].getMaximum());
        }

        return Vector<T>(vec);
    }

/** @name Equality
*/
    inline bool operator==(Bounds<T> const& rhs) const
    {
        return equal(rhs);
    }

    inline bool operator!=(Bounds<T> const& rhs) const
    {
        return (!equal(rhs));
    }

/** @name Identity
*/
    Bounds<T>& operator=(Bounds<T> const& rhs)
    {
        if (&rhs != this)
        {
            m_ranges = rhs.m_ranges;
        }
        return *this;
    }

/** @name Data queries
*/
    /// The vector of Range<T> for the Bounds
    RangeVector const& dimensions() const
    {
        return m_ranges;
    }

    /// The number of dimensions of the Bounds
    std::size_t size() const
    {
        return m_ranges.size();
    }

    /// Is this Bounds equal to other?
    bool equal(Bounds<T> const& other) const
    {
        if (size() != other.size())
        {
          return false;
        }
        for (std::size_t i = 0; i < size(); i++)
        {
            if (m_ranges[i] != other.m_ranges[i])
            {
                return false;
            }
        }
        return true;
    }

    /// Synonym for intersects for now
    bool overlaps(Bounds const& other) const
    {
        if (other.size() != size())
        {
            return false;
        }

        for (std::size_t i = 0; i < size(); i++)
        {
            if ( m_ranges[i].overlaps(other.m_ranges[i]) )
                return true;
        }

        return false;
    }

    /// Does this Bounds contain a point?
    bool contains(Vector<T> point) const
    {
        if (point.size() != size())
            return false;

        for (std::size_t i = 0; i < size(); i++)
        {
            // As soon as it is not contains, we're false
            if (! m_ranges[i].contains(point[i]) )
                return false;
        }
        return true;
    }

    /// Does this Bounds contain other?
    bool contains(Bounds<T> const& other) const
    {
        for (std::size_t i = 0; i < size(); i++)
        {
            // As soon as it is not contains, we're false
            if (! m_ranges[i].contains(other.m_ranges[i]) )
                return false;
        }
        return true;
    }

    /// Shift each dimension by a vector of deltas
    void shift(std::vector<T> deltas)
    {
        std::size_t i;
        if( size() != deltas.size())
        {
            std::ostringstream msg;
            msg << "pdal::Bounds::shift: Delta vector size, " << deltas.size()
                << ", is larger than the dimensionality of the bounds, "<< size() << ".";
            throw pdal::bounds_error(msg.str());
        }
        for (i = 0; i < deltas.size(); ++i)
        {
            m_ranges[i].shift(deltas[i]);
        }
    }

    /// Scale each dimension by a vector of deltas
    void scale(std::vector<T> deltas)
    {
        std::size_t i;
        if( size() != deltas.size())
        {
            std::ostringstream msg;
            msg << "pdal::Bounds::scale: Delta vector size, " << deltas.size()
                << ", is larger than the dimensionality of the bounds, "<< size() << ".";
            throw pdal::bounds_error(msg.str());
        }
        for (i = 0; i < deltas.size(); ++i)
        {
            m_ranges[i].scale(deltas[i]);
        }
    }

    /// Clip this Bounds to the extent of r
    void clip(Bounds const& r)
    {
        RangeVector ds = r.dimensions();
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].clip(ds[i]);
        }
    }

    /// Grow to the union of two pdal::Bounds
    void grow(Bounds const& r)
    {
        RangeVector ds = r.dimensions();
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].grow(ds[i]);
        }
    }

    /// Expand the pdal::Bounds to include this point
    void grow(Vector<T> const& point)
    {
        assert(point.size() == size());
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].grow(point[i]);
        }
    }

    /// Calculate a n-dimensional volume for the Bounds instance
    T volume() const
    {
        T output = T(1);
        for (std::size_t i = 0; i < size(); i++)
        {
            output = output * m_ranges[i].length();
        }

        return output;
    }

    /// Returns true if the pdal::Bounds<T>::size() is 0 or
    /// all dimensions within the bounds are empty.
    bool empty() const
    {
        if (size()==0)
        {
          return true;
        }

        for (std::size_t i = 0; i < size(); i++)
        {
            if (m_ranges[i].empty())
            {
                return true;
            }
        }
        return false;
    }

    /// Verifies that the minimums and maximums of each dimension within the
    /// bounds are not inverted (also works in the case where the bounds is
    /// at infinity or when the bounds is empty).
    bool verify()
    {
        for (std::size_t d = 0; d < size(); ++d)
        {
            if (getMinimum(d) > getMaximum(d) )
            {
                // Check that we're not infinity either way
                if (Utils::compare_distance<T>(getMinimum(d), (std::numeric_limits<T>::max)()) ||
                    Utils::compare_distance<T>(getMaximum(d), -(std::numeric_limits<T>::max)()))
                {
                    std::ostringstream msg;
                    msg << "pdal::Bounds::verify: Minimum point at dimension " << d
                        << "is greater than maximum point.  Neither point is infinity.";
                    throw pdal::bounds_error(msg.str());
                }
            }
        }
        return true;
    }

/** @name Default extent
*/
    /// Returns a staticly-allocated Bounds extent that represents infinity
    static const Bounds<T>& getDefaultSpatialExtent()
    {
        static T minv((std::numeric_limits<T>::min)());
        static T maxv((std::numeric_limits<T>::max)());
        static Bounds v(minv,minv,minv,maxv,maxv,maxv);
        return v;
    }

/** @name Summary and serialization
*/
    /// Outputs a string-based boost::property_tree::ptree representation
    /// of the Bounds instance
    boost::property_tree::ptree toPTree() const
    {
        boost::property_tree::ptree tree;
        for (std::size_t i = 0; i < size(); ++i)
        {
            const Range<T>& r = dimensions()[i];
            tree.add_child(boost::lexical_cast<std::string>(i), r.toPTree());
        }
        return tree;
    }

    /// Outputs a string representation of the Bounds instance to std::cout
    void dump() const
    {
        std::cout << *this;
    }
};

template<class T>
std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds)
{
    ostr << "(";
    for (std::size_t d = 0; d < bounds.size(); ++d)
    {
        const Range<T>& r = bounds.dimensions()[d];
        ostr << r;
        if (d!=bounds.size()-1) ostr << ", ";
    }
    ostr << ")";
    return ostr;
}

extern PDAL_DLL std::istream& operator>>(std::istream& istr, Bounds<double>& bounds);

} // namespace pdal

// Needed for C++ DLL exports
#ifdef PDAL_COMPILER_MSVC
template class PDAL_DLL pdal::Range<double>;
template class PDAL_DLL pdal::Bounds<double>;
#endif

#endif
<commit_msg>allow +inf, -inf bounds instances for cumulators<commit_after>/******************************************************************************
 * $Id$
 *
 * Project:  pdal - http://pdal.org - A BSD library for LAS format data.
 * Purpose:  LAS bounds class
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Martin Isenburg or Iowa Department
 *       of Natural Resources nor the names of its contributors may be
 *       used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef INCLUDED_BOUNDS_HPP
#define INCLUDED_BOUNDS_HPP

#include <pdal/pdal_internal.hpp>

#include <cassert>
#include <vector>
#include <sstream>
#include <boost/property_tree/ptree.hpp>

#include <pdal/Vector.hpp>
#include <pdal/Range.hpp>

namespace pdal
{

/// Bounds is for manipulating n-dimensional ranges of data.  Typically
/// used for defining the spatial extents of XYZ data, this class can also be
/// used for defining bounds of other dimensions.
template <typename T>
class PDAL_DLL Bounds
{
public:
    typedef typename std::vector< Range<T> > RangeVector;

private:
    RangeVector m_ranges;

public:

/** @name Constructors
*/

    /// Constructs an empty Bounds instance
    /// with no dimensions
    Bounds<T>()
    {
        m_ranges.resize(0);
    }

    /// Copy constructor
    Bounds(Bounds const& other)
        : m_ranges(other.m_ranges)
    {
    }

    /// Constructs a Bounds instance from a vector
    /// of Range
    Bounds(RangeVector const& ranges)
        :
        m_ranges(ranges)
    {
    }

    /// Convenience constructor for typical 3D case
    Bounds( T minx,
            T miny,
            T minz,
            T maxx,
            T maxy,
            T maxz)
    {
        m_ranges.resize(3);

        m_ranges[0].setMinimum(minx);
        m_ranges[1].setMinimum(miny);
        m_ranges[2].setMinimum(minz);

        m_ranges[0].setMaximum(maxx);
        m_ranges[1].setMaximum(maxy);
        m_ranges[2].setMaximum(maxz);

        assert(verify());

    }

    /// Convenience constructor for typical 2D case
    Bounds( T minx,
            T miny,
            T maxx,
            T maxy)
    {

        m_ranges.resize(2);

        m_ranges[0].setMinimum(minx);
        m_ranges[1].setMinimum(miny);

        m_ranges[0].setMaximum(maxx);
        m_ranges[1].setMaximum(maxy);

        assert(verify());
    }

    /// Convenience constructor for Vector of minimum and maximum
    /// values.
    Bounds(const Vector<T>& minimum, const Vector<T>& maximum)
    {
        assert(minimum.size() == maximum.size());

        m_ranges.resize(minimum.size());

        for (std::size_t i=0; i<minimum.size(); i++)
        {
            m_ranges[i].setMinimum(minimum[i]);
            m_ranges[i].setMaximum(maximum[i]);
        }

        assert(verify());
    }

/** @name Data manipulation
*/

    T getMinimum(std::size_t const& index) const
    {
        if (m_ranges.size() <= index)
        {
            // std::ostringstream msg;
            // msg << "Bounds dimensions, " << ranges.size() <<", is less "
            //     << "than the given index, " << index;
            // throw pdal::bounds_error(msg.str());
            return 0;
        }
        return m_ranges[index].getMinimum();
    }

    void setMinimum(std::size_t const& index, T v)
    {
        if (m_ranges.size() <= index)
        {
            m_ranges.resize(index + 1);
        }
        m_ranges[index].setMinimum(v);
    }

    T getMaximum(std::size_t const& index) const
    {
        if (m_ranges.size() <= index)
        {
            // std::ostringstream msg;
            // msg << "Bounds dimensions, " << m_ranges.size() <<", is less "
            //     << "than the given index, " << index;
            // throw pdal::bounds_error(msg.str());
            return 0;
        }
        return m_ranges[index].getMaximum();
    }

    void setMaximum(std::size_t const& index, T v)
    {
        if (m_ranges.size() <= index)
        {
            m_ranges.resize(index + 1);
        }
        m_ranges[index].setMaximum(v);
    }

    Vector<T> getMinimum()
    {
        std::vector<T> vec;

        for (std::size_t i=0; i<m_ranges.size(); i++)
        {
            vec.push_back(m_ranges[i].getMinimum());
        }

        return Vector<T>(vec);
    }

    Vector<T> getMaximum()
    {
        std::vector<T> vec;

        for (std::size_t i=0; i<m_ranges.size(); i++)
        {
            vec.push_back(m_ranges[i].getMaximum());
        }

        return Vector<T>(vec);
    }

/** @name Equality
*/
    inline bool operator==(Bounds<T> const& rhs) const
    {
        return equal(rhs);
    }

    inline bool operator!=(Bounds<T> const& rhs) const
    {
        return (!equal(rhs));
    }

/** @name Identity
*/
    Bounds<T>& operator=(Bounds<T> const& rhs)
    {
        if (&rhs != this)
        {
            m_ranges = rhs.m_ranges;
        }
        return *this;
    }

/** @name Data queries
*/
    /// The vector of Range<T> for the Bounds
    RangeVector const& dimensions() const
    {
        return m_ranges;
    }

    /// The number of dimensions of the Bounds
    std::size_t size() const
    {
        return m_ranges.size();
    }

    /// Is this Bounds equal to other?
    bool equal(Bounds<T> const& other) const
    {
        if (size() != other.size())
        {
          return false;
        }
        for (std::size_t i = 0; i < size(); i++)
        {
            if (m_ranges[i] != other.m_ranges[i])
            {
                return false;
            }
        }
        return true;
    }

    /// Synonym for intersects for now
    bool overlaps(Bounds const& other) const
    {
        if (other.size() != size())
        {
            return false;
        }

        for (std::size_t i = 0; i < size(); i++)
        {
            if ( m_ranges[i].overlaps(other.m_ranges[i]) )
                return true;
        }

        return false;
    }

    /// Does this Bounds contain a point?
    bool contains(Vector<T> point) const
    {
        if (point.size() != size())
            return false;

        for (std::size_t i = 0; i < size(); i++)
        {
            // As soon as it is not contains, we're false
            if (! m_ranges[i].contains(point[i]) )
                return false;
        }
        return true;
    }

    /// Does this Bounds contain other?
    bool contains(Bounds<T> const& other) const
    {
        for (std::size_t i = 0; i < size(); i++)
        {
            // As soon as it is not contains, we're false
            if (! m_ranges[i].contains(other.m_ranges[i]) )
                return false;
        }
        return true;
    }

    /// Shift each dimension by a vector of deltas
    void shift(std::vector<T> deltas)
    {
        std::size_t i;
        if( size() != deltas.size())
        {
            std::ostringstream msg;
            msg << "pdal::Bounds::shift: Delta vector size, " << deltas.size()
                << ", is larger than the dimensionality of the bounds, "<< size() << ".";
            throw pdal::bounds_error(msg.str());
        }
        for (i = 0; i < deltas.size(); ++i)
        {
            m_ranges[i].shift(deltas[i]);
        }
    }

    /// Scale each dimension by a vector of deltas
    void scale(std::vector<T> deltas)
    {
        std::size_t i;
        if( size() != deltas.size())
        {
            std::ostringstream msg;
            msg << "pdal::Bounds::scale: Delta vector size, " << deltas.size()
                << ", is larger than the dimensionality of the bounds, "<< size() << ".";
            throw pdal::bounds_error(msg.str());
        }
        for (i = 0; i < deltas.size(); ++i)
        {
            m_ranges[i].scale(deltas[i]);
        }
    }

    /// Clip this Bounds to the extent of r
    void clip(Bounds const& r)
    {
        RangeVector ds = r.dimensions();
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].clip(ds[i]);
        }
    }

    /// Grow to the union of two pdal::Bounds
    void grow(Bounds const& r)
    {
        RangeVector ds = r.dimensions();
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].grow(ds[i]);
        }
    }

    /// Expand the pdal::Bounds to include this point
    void grow(Vector<T> const& point)
    {
        assert(point.size() == size());
        for (std::size_t i = 0; i < size(); ++i)
        {
            m_ranges[i].grow(point[i]);
        }
    }

    /// Calculate a n-dimensional volume for the Bounds instance
    T volume() const
    {
        T output = T(1);
        for (std::size_t i = 0; i < size(); i++)
        {
            output = output * m_ranges[i].length();
        }

        return output;
    }

    /// Returns true if the pdal::Bounds<T>::size() is 0 or
    /// all dimensions within the bounds are empty.
    bool empty() const
    {
        if (size()==0)
        {
          return true;
        }

        for (std::size_t i = 0; i < size(); i++)
        {
            if (m_ranges[i].empty())
            {
                return true;
            }
        }
        return false;
    }

    /// Verifies that the minimums and maximums of each dimension within the
    /// bounds are not inverted (allows min == +inf and max == -inf, however).
    bool verify()
    {
        for (std::size_t d = 0; d < size(); ++d)
        {
            if (getMinimum(d) > getMaximum(d) )
            {
                // Allow infinity bounds
                if (!Utils::compare_distance<T>(getMinimum(d), (std::numeric_limits<T>::max)()) &&
                    !Utils::compare_distance<T>(getMaximum(d), -(std::numeric_limits<T>::min)()))
                {
                    std::ostringstream msg;
                    msg << "pdal::Bounds::verify: Minimum point at dimension " << d
                        << " is greater than maximum point.  Neither point is infinity.";
                    throw pdal::bounds_error(msg.str());
                }
            }
        }
        return true;
    }

/** @name Default extent
*/
    /// Returns a staticly-allocated Bounds extent that represents infinity
    static const Bounds<T>& getDefaultSpatialExtent()
    {
        static T minv((std::numeric_limits<T>::min)());
        static T maxv((std::numeric_limits<T>::max)());
        static Bounds v(minv,minv,minv,maxv,maxv,maxv);
        return v;
    }

/** @name Summary and serialization
*/
    /// Outputs a string-based boost::property_tree::ptree representation
    /// of the Bounds instance
    boost::property_tree::ptree toPTree() const
    {
        boost::property_tree::ptree tree;
        for (std::size_t i = 0; i < size(); ++i)
        {
            const Range<T>& r = dimensions()[i];
            tree.add_child(boost::lexical_cast<std::string>(i), r.toPTree());
        }
        return tree;
    }

    /// Outputs a string representation of the Bounds instance to std::cout
    void dump() const
    {
        std::cout << *this;
    }
};

template<class T>
std::ostream& operator<<(std::ostream& ostr, const Bounds<T>& bounds)
{
    ostr << "(";
    for (std::size_t d = 0; d < bounds.size(); ++d)
    {
        const Range<T>& r = bounds.dimensions()[d];
        ostr << r;
        if (d!=bounds.size()-1) ostr << ", ";
    }
    ostr << ")";
    return ostr;
}

extern PDAL_DLL std::istream& operator>>(std::istream& istr, Bounds<double>& bounds);

} // namespace pdal

// Needed for C++ DLL exports
#ifdef PDAL_COMPILER_MSVC
template class PDAL_DLL pdal::Range<double>;
template class PDAL_DLL pdal::Bounds<double>;
#endif

#endif
<|endoftext|>


<commit_before>/* sunfish.cpp
 *
 * Kubo Ryosuke
 */

#include "sunfish.h"
#include "config.h"
#include "console/ConsoleManager.h"
#include "program_options/ProgramOptions.h"
#include "logger/Logger.h"
#include <iostream>
#include <string>

using namespace sunfish;

int play(const ConsoleManager::Config&);

// book.cpp
int generateBook(const std::string& directory);

// network.cpp
int network();

// learning.cpp
int learn();
int analyzeEvalBin();

// solve.cpp
int solve(const std::vector<std::string>& problems, const ConsoleManager::Config&);

// profile.cpp
int profile(const ConsoleManager::Config&, bool);

// test.cpp
int test();

// dev.cpp
int exprMoveGenSpeed();
int generateZobrist();
int checkMoveGen();

/**
 * entry point
 */
int main(int argc, char** argv, char** /*envp*/) {
  std::cout << SUNFISH_NAME << ' ';
  std::cout << SUNFISH_VERSION << '\n';
  std::cout << SUNFISH_COPYRIGHT << '\n';
  std::cout << std::endl;

  // program options
  ProgramOptions po;
  po.addOption("in", "i", "record path", true);
  po.addOption("out", "o", "record path", true);
  po.addOption("black", "b", "[auto/manual]", true);
  po.addOption("white", "w", "[auto/manual]", true);
  po.addOption("depth", "d", "max depth (default: 15)", true);
  po.addOption("time", "t", "max time for 1 move (default: 3)", true);
  po.addOption("worker", "r", "the number of worker threads", true);
  po.addOption("book", "generate book", true);
  po.addOption("network", "n", "network mode");
#ifndef NLEARN
  po.addOption("learn", "l", "learning");
  po.addOption("analyze", "a", "");
#endif // NLEARN
  po.addOption("problem", "p", "solve problems");
  po.addOption("profile", "solve problems");
  po.addOption("profile1", "solve one problem");
#ifndef NDEBUG
  po.addOption("test", "unit test");
  po.addOption("dev", "development method", true);
#endif
  po.addOption("help", "h", "show this help.");
  po.parse(argc, argv);

  for (const auto& invalidArg : po.getInvalidArgs()) {
    std::cerr << "WARNING: `" << invalidArg.arg << "' is invalid argument: " << invalidArg.reason << std::endl;
  }

  if (po.has("help")) {
    // show help
    std::cerr << po.help() << std::endl;
    return 0;

  } else if (po.has("book")) {
    std::string directory = po.getValue("book");
    return generateBook(directory);

  } else if (po.has("network")) {
    return network();

#ifndef NLEARN
  } else if (po.has("learn")) {
    return learn();

  } else if (po.has("analyze")) {
    return analyzeEvalBin();

#endif // NLEARN
#ifndef NDEBUG
  } else if (po.has("test")) {
    // unit test
    return test();

  } else if (po.has("dev")) {
    // development
    std::string code = po.getValue("dev");

    if (code == "gen_speed_test") {
      return exprMoveGenSpeed();

    } else if (code == "zobrist") {
      return generateZobrist();

    } else if (code == "gen_check") {
      return checkMoveGen();

    } else {
      std::cerr << '"' << code << "\" is unknown code." << std::endl;
      return 1;

    }

#endif
  }

  auto config = ConsoleManager::getDefaultConfig();

  // 起動時に読み込む棋譜ファイル
  if (po.has("in")) {
    config.inFileName = po.getValue("in");
    config.autoBlack = false;
    config.autoWhite = false;
  }

  // 自動保存する棋譜ファイル
  if (po.has("out")) {
    config.outFileName = po.getValue("out");
  }

  // 先手番自動対局 or マニュアル
  if (po.has("black")) {
    std::string value = po.getValue("black");
    if (value == "auto") {
      config.autoBlack = true;
    } else if (value == "manual") {
      config.autoBlack = false;
    } else {
      std::cerr << value << " is unknown value for --black option." << std::endl;
    }
  }

  // 後手番自動対局 or マニュアル
  if (po.has("white")) {
    std::string value = po.getValue("white");
    if (value == "auto") {
      config.autoWhite = true;
    } else if (value == "manual") {
      config.autoWhite = false;
    } else {
      std::cerr << value << " is unknown value for --white option." << std::endl;
    }
  }

  // 最大探索深さ
  if (po.has("depth")) {
    int depth = std::stoi(po.getValue("depth"));
    config.maxDepth = depth;
  }

  // worker
  if (po.has("worker")) {
    int worker = std::stoi(po.getValue("worker"));
    config.worker = worker;
  }

  // 最大思考時間
  if (po.has("time")) {
    config.limitSeconds = std::stod(po.getValue("time"));
  }

  if (po.has("problem")) {
    // 問題解答
    return solve(po.getStdArgs(), config);
  }

  if (po.has("profile")) {
    // profiling
    return profile(config, true);
  }

  if (po.has("profile1")) {
    // profiling
    return profile(config, false);
  }

  return play(config);
}

/**
 * コンソール上での対局を行います。
 */
int play(const ConsoleManager::Config& config) {

  // init loggers
  Loggers::error.addStream(std::cerr, ESC_SEQ_COLOR_RED, ESC_SEQ_COLOR_RESET);
  Loggers::warning.addStream(std::cerr, ESC_SEQ_COLOR_YELLOW, ESC_SEQ_COLOR_RESET);
  Loggers::message.addStream(std::cerr);
  Loggers::send.addStream(std::cerr, true, true, ESC_SEQ_COLOR_BLUE, ESC_SEQ_COLOR_RESET);
  Loggers::receive.addStream(std::cerr, true, true, ESC_SEQ_COLOR_MAGENTA, ESC_SEQ_COLOR_RESET);
#ifndef NDEBUG
  Loggers::debug.addStream(std::cerr, ESC_SEQ_COLOR_CYAN, ESC_SEQ_COLOR_RESET);
  Loggers::test.addStream(std::cerr, ESC_SEQ_COLOR_GREEN, ESC_SEQ_COLOR_RESET);
  Loggers::develop.addStream(std::cerr, ESC_SEQ_COLOR_WHITE, ESC_SEQ_COLOR_RESET);
#endif

  ConsoleManager console;
  console.setConfig(config);

  bool ok = console.play();

  return ok ? 0 : 1;
}
<commit_msg>Fix output stream<commit_after>/* sunfish.cpp
 *
 * Kubo Ryosuke
 */

#include "sunfish.h"
#include "config.h"
#include "console/ConsoleManager.h"
#include "program_options/ProgramOptions.h"
#include "logger/Logger.h"
#include <iostream>
#include <string>

using namespace sunfish;

int play(const ConsoleManager::Config&);

// book.cpp
int generateBook(const std::string& directory);

// network.cpp
int network();

// learning.cpp
int learn();
int analyzeEvalBin();

// solve.cpp
int solve(const std::vector<std::string>& problems, const ConsoleManager::Config&);

// profile.cpp
int profile(const ConsoleManager::Config&, bool);

// test.cpp
int test();

// dev.cpp
int exprMoveGenSpeed();
int generateZobrist();
int checkMoveGen();

/**
 * entry point
 */
int main(int argc, char** argv, char** /*envp*/) {
  std::cerr << SUNFISH_NAME << ' ';
  std::cerr << SUNFISH_VERSION << '\n';
  std::cerr << SUNFISH_COPYRIGHT << '\n';
  std::cerr << std::endl;

  // program options
  ProgramOptions po;
  po.addOption("in", "i", "record path", true);
  po.addOption("out", "o", "record path", true);
  po.addOption("black", "b", "[auto/manual]", true);
  po.addOption("white", "w", "[auto/manual]", true);
  po.addOption("depth", "d", "max depth (default: 15)", true);
  po.addOption("time", "t", "max time for 1 move (default: 3)", true);
  po.addOption("worker", "r", "the number of worker threads", true);
  po.addOption("book", "generate book", true);
  po.addOption("network", "n", "network mode");
#ifndef NLEARN
  po.addOption("learn", "l", "learning");
  po.addOption("analyze", "a", "");
#endif // NLEARN
  po.addOption("problem", "p", "solve problems");
  po.addOption("profile", "solve problems");
  po.addOption("profile1", "solve one problem");
#ifndef NDEBUG
  po.addOption("test", "unit test");
  po.addOption("dev", "development method", true);
#endif
  po.addOption("help", "h", "show this help.");
  po.parse(argc, argv);

  for (const auto& invalidArg : po.getInvalidArgs()) {
    std::cerr << "WARNING: `" << invalidArg.arg << "' is invalid argument: " << invalidArg.reason << std::endl;
  }

  if (po.has("help")) {
    // show help
    std::cerr << po.help() << std::endl;
    return 0;

  } else if (po.has("book")) {
    std::string directory = po.getValue("book");
    return generateBook(directory);

  } else if (po.has("network")) {
    return network();

#ifndef NLEARN
  } else if (po.has("learn")) {
    return learn();

  } else if (po.has("analyze")) {
    return analyzeEvalBin();

#endif // NLEARN
#ifndef NDEBUG
  } else if (po.has("test")) {
    // unit test
    return test();

  } else if (po.has("dev")) {
    // development
    std::string code = po.getValue("dev");

    if (code == "gen_speed_test") {
      return exprMoveGenSpeed();

    } else if (code == "zobrist") {
      return generateZobrist();

    } else if (code == "gen_check") {
      return checkMoveGen();

    } else {
      std::cerr << '"' << code << "\" is unknown code." << std::endl;
      return 1;

    }

#endif
  }

  auto config = ConsoleManager::getDefaultConfig();

  // 起動時に読み込む棋譜ファイル
  if (po.has("in")) {
    config.inFileName = po.getValue("in");
    config.autoBlack = false;
    config.autoWhite = false;
  }

  // 自動保存する棋譜ファイル
  if (po.has("out")) {
    config.outFileName = po.getValue("out");
  }

  // 先手番自動対局 or マニュアル
  if (po.has("black")) {
    std::string value = po.getValue("black");
    if (value == "auto") {
      config.autoBlack = true;
    } else if (value == "manual") {
      config.autoBlack = false;
    } else {
      std::cerr << value << " is unknown value for --black option." << std::endl;
    }
  }

  // 後手番自動対局 or マニュアル
  if (po.has("white")) {
    std::string value = po.getValue("white");
    if (value == "auto") {
      config.autoWhite = true;
    } else if (value == "manual") {
      config.autoWhite = false;
    } else {
      std::cerr << value << " is unknown value for --white option." << std::endl;
    }
  }

  // 最大探索深さ
  if (po.has("depth")) {
    int depth = std::stoi(po.getValue("depth"));
    config.maxDepth = depth;
  }

  // worker
  if (po.has("worker")) {
    int worker = std::stoi(po.getValue("worker"));
    config.worker = worker;
  }

  // 最大思考時間
  if (po.has("time")) {
    config.limitSeconds = std::stod(po.getValue("time"));
  }

  if (po.has("problem")) {
    // 問題解答
    return solve(po.getStdArgs(), config);
  }

  if (po.has("profile")) {
    // profiling
    return profile(config, true);
  }

  if (po.has("profile1")) {
    // profiling
    return profile(config, false);
  }

  return play(config);
}

/**
 * コンソール上での対局を行います。
 */
int play(const ConsoleManager::Config& config) {

  // init loggers
  Loggers::error.addStream(std::cerr, ESC_SEQ_COLOR_RED, ESC_SEQ_COLOR_RESET);
  Loggers::warning.addStream(std::cerr, ESC_SEQ_COLOR_YELLOW, ESC_SEQ_COLOR_RESET);
  Loggers::message.addStream(std::cerr);
  Loggers::send.addStream(std::cerr, true, true, ESC_SEQ_COLOR_BLUE, ESC_SEQ_COLOR_RESET);
  Loggers::receive.addStream(std::cerr, true, true, ESC_SEQ_COLOR_MAGENTA, ESC_SEQ_COLOR_RESET);
#ifndef NDEBUG
  Loggers::debug.addStream(std::cerr, ESC_SEQ_COLOR_CYAN, ESC_SEQ_COLOR_RESET);
  Loggers::test.addStream(std::cerr, ESC_SEQ_COLOR_GREEN, ESC_SEQ_COLOR_RESET);
  Loggers::develop.addStream(std::cerr, ESC_SEQ_COLOR_WHITE, ESC_SEQ_COLOR_RESET);
#endif

  ConsoleManager console;
  console.setConfig(config);

  bool ok = console.play();

  return ok ? 0 : 1;
}
<|endoftext|>


<commit_before>#include "ModuleManager.hpp"

#include <QPluginLoader>
#include <QApplication>
#include <QObject>
#include <QDir>
#include <QObjectList>
#include <QStringList>
#include <string>
#include "Logger.hpp"
#include "ModuleBase.hpp"

using namespace uipf;
using namespace std;

// loads the configuration and stores in the ModuleManager
/*
conf	Configuration file, which has to be executed
*/
ModuleManager::ModuleManager(Configuration conf)
 : config_(conf)
{
	initModules();
}

// executes the Configuration file
/*
*/
void ModuleManager::run(){

	// TODO sort processing steps

	// get processing chain
	map<string, ProcessingStep> chain = config_.getProcessingChain();

	Context context;

	// iterate over all modules and run them
	map<string, ProcessingStep>::iterator it = chain.begin();
	for (; it!=chain.end(); ++it) {

		// load the module
		ModuleInterface* mod = loadModule(it->second.module);
		ModuleBase* modbase = dynamic_cast<ModuleBase*>(mod);
		if (modbase)
			modbase->setContext(&context);

		// TODO fill outputs with inputs from other modules
		map<string, Data::ptr > inputs;
		map<string, Data::ptr > outputs;

		LOG_I( "Running step '" + it->first + "'..." );
		mod->run(inputs, it->second.params, outputs);
		LOG_I( "Done with step '" + it->first + "'." );

		// TODO store outputs somewhere
	}

}

void ModuleManager::initModules()
{
   QDir pluginsDir = QDir(qApp->applicationDirPath());

    foreach (QString fileName, pluginsDir.entryList(QDir::Files))
    {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
		Logger::instance()->Info("found: " + fileName.toStdString());
		ModuleInterface* iModule =
		    qobject_cast<ModuleInterface* >(plugin);

		//2DO: use metadata as key
		plugins_.insert( std::pair<std::string, ModuleInterface* >(iModule->name(), iModule) );

        }

    }

}

ModuleInterface* ModuleManager::loadModule(const std::string& name){

Logger::instance()->Info("loadModule: " + name);

return plugins_[name]; //2DO: safety, uppercase lowercase etc.

}

MetaData ModuleManager::getModuleMetaData(const std::string& name){

	// TODO this is dummy

	map<string, Type> in;
	in.insert( pair<string, Type>("image", MATRIX) );

	map<string, Type> out;
	out.insert( pair<string, Type>("image", MATRIX) );

	MetaData meta("Dummy module description for " + name, in, out);

	return meta;

}

<commit_msg>implemented sorting + input/output matching  in module manager<commit_after>#include "ModuleManager.hpp"

#include <QPluginLoader>
#include <QApplication>
#include <QObject>
#include <QDir>
#include <QObjectList>
#include <QStringList>
#include <string>
#include "Logger.hpp"
#include "ModuleBase.hpp"

using namespace uipf;
using namespace std;

// loads the configuration and stores in the ModuleManager
/*
conf	Configuration file, which has to be executed
*/
ModuleManager::ModuleManager(Configuration conf)
 : config_(conf)
{
	initModules();
}

// executes the Configuration file
/*
*/
void ModuleManager::run(){

	// get processing chain
	map<string, ProcessingStep> chain = config_.getProcessingChain();

	map<string, ProcessingStep> chainTmp;
	chainTmp.insert(chain.begin(), chain.end());

	// contains the names of the processing steps in the correct order
	vector<string> sortedChain;

	// iterate over all processing steps and order them
	while(!chainTmp.empty()){
		map<string, ProcessingStep>::iterator itProSt = chainTmp.begin();

		for (; itProSt!=chainTmp.end(); ++itProSt) {

			// add all modules without any dependencies
			if(itProSt->second.inputs.size() == 0){
				sortedChain.push_back(itProSt->first);
				chainTmp.erase(itProSt);
			} else {
				// go through dependencies, and add only the modules, where module
				// on which they depend have already been added
				map<string, pair<string,string> >::iterator it = itProSt->second.inputs.begin();
				int i = 1;
				for (; it!=itProSt->second.inputs.end(); ++it) {
					if (sortedChain.count(it->second.first)){
						i *=1;
					} else{
						i *=0;
					}
				}
				if (i == 1){
					sortedChain.push_back(itProSt->first);
					chainTmp.erase(itProSt);
				}
			}
		}
	}

	Context context;

	// contains the outputs of the processing steps
	map<string, map<string, Data::ptr> > stepsOutputs;

	// run over the sortedChain and run the modules in the order given by the chain
	for (int i=0; i<sortedChain.size(); i++){

		ProcessingStep proSt = chain[sortedChain[i]];

		// load the module
		ModuleInterface* mod = loadModule(proSt.module);
		ModuleBase* modbase = dynamic_cast<ModuleBase*>(mod);
		if (modbase){
			modbase->setContext(&context);
		}

		map<string, Data::ptr > inputs;
		map<string, Data::ptr > outputs;

		// fill the inputs of the current processing step
		map<string, pair<string, string> >::iterator it = proSt.inputs.begin();
		for (; it!=proSt.inputs.end(); ++it) {
			inputs.insert(pair<string, Data::ptr> (it->first, stepOutputs[it->second.first][it->second.second]));
		}

		LOG_I( "Running step '" + proSt.name + "'..." );
		mod->run(inputs, proSt.params, outputs);
		LOG_I( "Done with step '" + proSt.name + "'." );

		// fill the outputs of the current processing step
		stepOutputs.insert(pair<string, map<string, Data::ptr> > (proSt.name, outputs));
	}

}

void ModuleManager::initModules()
{
   QDir pluginsDir = QDir(qApp->applicationDirPath());

    foreach (QString fileName, pluginsDir.entryList(QDir::Files))
    {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = loader.instance();
        if (plugin) {
		Logger::instance()->Info("found: " + fileName.toStdString());
		ModuleInterface* iModule =
		    qobject_cast<ModuleInterface* >(plugin);

		//2DO: use metadata as key
		plugins_.insert( std::pair<std::string, ModuleInterface* >(iModule->name(), iModule) );

        }

    }

}

ModuleInterface* ModuleManager::loadModule(const std::string& name){

Logger::instance()->Info("loadModule: " + name);

return plugins_[name]; //2DO: safety, uppercase lowercase etc.

}

MetaData ModuleManager::getModuleMetaData(const std::string& name){

	// TODO this is dummy

	map<string, Type> in;
	in.insert( pair<string, Type>("image", MATRIX) );

	map<string, Type> out;
	out.insert( pair<string, Type>("image", MATRIX) );

	MetaData meta("Dummy module description for " + name, in, out);

	return meta;

}

<|endoftext|>