<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2020  David Shah <dave@ds0.me>
 *
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "log.h"
#include "nextpnr.h"

#include <iterator>

NEXTPNR_NAMESPACE_BEGIN

struct TCLEntity
{
    enum EntityType
    {
        ENTITY_CELL,
        ENTITY_PORT,
        ENTITY_NET,
    } type;
    IdString name;

    TCLEntity(EntityType type, IdString name) : type(type), name(name) {}

    const std::string &to_string(Context *ctx) { return name.str(ctx); }

    CellInfo *get_cell(Context *ctx)
    {
        if (type != ENTITY_CELL)
            return nullptr;
        return ctx->cells.at(name).get();
    }

    PortInfo *get_port(Context *ctx)
    {
        if (type != ENTITY_PORT)
            return nullptr;
        return &ctx->ports.at(name);
    }

    NetInfo *get_net(Context *ctx)
    {
        if (type != ENTITY_NET)
            return nullptr;
        return ctx->nets.at(name).get();
    }
};

struct TCLValue
{
    TCLValue(const std::string &s) : is_string(true), str(s){};
    TCLValue(const std::vector<TCLEntity> &l) : is_string(false), list(l){};

    bool is_string;
    std::string str;             // simple string value
    std::vector<TCLEntity> list; // list of entities
};

struct PDCParser
{
    std::string buf;
    int pos = 0;
    int lineno = 1;
    Context *ctx;

    PDCParser(const std::string &buf, Context *ctx) : buf(buf), ctx(ctx){};

    inline bool eof() const { return pos == int(buf.size()); }

    inline char peek() const { return buf.at(pos); }

    inline char get()
    {
        char c = buf.at(pos++);
        if (c == '\n')
            ++lineno;
        return c;
    }

    std::string get(int n)
    {
        std::string s = buf.substr(pos, n);
        pos += n;
        return s;
    }

    // If next char matches c, take it from the stream and return true
    bool check_get(char c)
    {
        if (peek() == c) {
            get();
            return true;
        } else {
            return false;
        }
    }

    // If next char matches any in chars, take it from the stream and return true
    bool check_get_any(const std::string &chrs)
    {
        char c = peek();
        if (chrs.find(c) != std::string::npos) {
            get();
            return true;
        } else {
            return false;
        }
    }

    inline void skip_blank(bool nl = false)
    {
        while (!eof() && check_get_any(nl ? " \t\n\r" : " \t"))
            ;
    }

    // Return true if end of line (or file)
    inline bool skip_check_eol()
    {
        skip_blank(false);
        if (eof())
            return true;
        char c = peek();
        // Comments count as end of line
        if (c == '#') {
            get();
            while (!eof() && peek() != '\n' && peek() != '\r')
                get();
            return true;
        }
        if (c == ';') {
            // Forced end of line
            get();
            return true;
        }
        return (c == '\n' || c == '\r');
    }

    inline std::string get_str()
    {
        std::string s;
        skip_blank(false);
        if (eof())
            return "";

        bool in_quotes = false, in_braces = false, escaped = false;

        char c = get();

        if (c == '"')
            in_quotes = true;
        else if (c == '{')
            in_braces = true;
        else
            s += c;

        while (true) {
            char c = peek();
            if (!in_quotes && !in_braces && !escaped && (std::isblank(c) || c == ']')) {
                break;
            }
            get();
            if (escaped) {
                s += c;
                escaped = false;
            } else if ((in_quotes && c == '"') || (in_braces && c == '}')) {
                break;
            } else if (c == '\\') {
                escaped = true;
            } else {
                s += c;
            }
        }

        return s;
    }

    TCLValue evaluate(const std::vector<TCLValue> &arguments)
    {
        NPNR_ASSERT(!arguments.empty());
        auto &arg0 = arguments.at(0);
        NPNR_ASSERT(arg0.is_string);
        const std::string &cmd = arg0.str;
        if (cmd == "get_ports")
            return cmd_get_ports(arguments);
        else if (cmd == "get_cells")
            return cmd_get_cells(arguments);
        else if (cmd == "get_nets")
            return cmd_get_nets(arguments);
        else if (cmd == "create_clock")
            return cmd_create_clock(arguments);
        else if (cmd == "ldc_set_location")
            return cmd_ldc_set_location(arguments);
        else if (cmd == "ldc_set_port")
            return cmd_ldc_set_port(arguments);
        else if (cmd == "ldc_set_sysconfig" || cmd == "get_nets" || cmd == "create_clock") {
            log_warning("%s is not yet supported!\n", cmd.c_str());
            return TCLValue("");
        } else
            log_error("Unsupported PDC command '%s'\n", cmd.c_str());
    }

    std::vector<TCLValue> get_arguments()
    {
        std::vector<TCLValue> args;
        while (!skip_check_eol()) {
            if (check_get('[')) {
                // Start of a sub-expression
                auto result = evaluate(get_arguments());
                NPNR_ASSERT(check_get(']'));
                args.push_back(result);
            } else if (peek() == ']') {
                break;
            } else {
                args.push_back(get_str());
            }
        }
        skip_blank(true);
        return args;
    }

    TCLValue cmd_get_nets(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> nets;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_nets expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_nets (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->nets.count(id) || ctx->net_aliases.count(id))
                nets.emplace_back(TCLEntity::ENTITY_NET, ctx->net_aliases.count(id) ? ctx->net_aliases.at(id) : id);
            else
                log_warning("get_nets argument '%s' matched no objects.\n", s.c_str());
        }
        return nets;
    }

    TCLValue cmd_get_ports(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> ports;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_ports expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_ports (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->ports.count(id))
                ports.emplace_back(TCLEntity::ENTITY_PORT, id);
        }
        return ports;
    }

    TCLValue cmd_get_cells(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> cells;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_cells expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_cells (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->cells.count(id))
                cells.emplace_back(TCLEntity::ENTITY_CELL, id);
        }
        return cells;
    }

    TCLValue cmd_create_clock(const std::vector<TCLValue> &arguments)
    {
        float period = 10;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-period") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -period (line %d)\n", lineno);
                    try {
                        period = std::stof(val.str);
                    } catch (std::exception &e) {
                        log_error("invalid argument '%s' to -period (line %d)\n", val.str.c_str(), lineno);
                    }
                } else if (s == "-name") {
                    i++;
                } else {
                    log_error("unsupported argument '%s' to create_clock\n", s.c_str());
                }
            } else {
                for (const auto &ety : arg.list) {
                    NetInfo *net = nullptr;
                    if (ety.type == TCLEntity::ENTITY_NET)
                        net = ctx->nets.at(ety.name).get();
                    else if (ety.type == TCLEntity::ENTITY_PORT)
                        net = ctx->ports.at(ety.name).net;
                    else
                        log_error("create_clock applies only to cells or IO ports (line %d)\n", lineno);
                    ctx->addClock(net->name, 1000.0f / period);
                }
            }
        }
        return std::string{};
    }

    TCLValue cmd_ldc_set_location(const std::vector<TCLValue> &arguments)
    {
        std::string site;

        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-site") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -site (line %d)\n", lineno);
                    site = val.str;
                }
            } else {
                if (site.empty())
                    log_error("expecting -site before list of objects (line %d)\n", lineno);
                for (const auto &ety : arg.list) {
                    if (ety.type == TCLEntity::ENTITY_PORT)
                        ctx->io_attr[ety.name][id_LOC] = site;
                    else if (ety.type == TCLEntity::ENTITY_CELL)
                        ctx->cells[ety.name]->attrs[id_LOC] = site;
                    else
                        log_error("ldc_set_location applies only to cells or IO ports (line %d)\n", lineno);
                }
            }
        }
        return std::string{};
    }

    TCLValue cmd_ldc_set_port(const std::vector<TCLValue> &arguments)
    {
        std::unordered_map<IdString, Property> args;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-iobuf") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -iobuf (line %d)\n", lineno);
                    std::stringstream ss(val.str);
                    std::string kv;
                    while (ss >> kv) {
                        auto eqp = kv.find('=');
                        if (eqp == std::string::npos)
                            log_error("expected key-value pair separated by '=' (line %d)", lineno);
                        std::string k = kv.substr(0, eqp), v = kv.substr(eqp + 1);
                        args[ctx->id(k)] = v;
                    }
                } else {
                    log_error("unexpected argument '%s' to ldc_set_port (line %d)\n", s.c_str(), lineno);
                }
            } else {
                for (const auto &ety : arg.list) {
                    if (ety.type == TCLEntity::ENTITY_PORT)
                        for (const auto &kv : args)
                            ctx->io_attr[ety.name][kv.first] = kv.second;
                    else
                        log_error("ldc_set_port applies only to IO ports (line %d)\n", lineno);
                }
            }
        }
        return std::string{};
    }

    void operator()()
    {
        while (!eof()) {
            skip_blank(true);
            auto args = get_arguments();
            if (args.empty())
                continue;
            evaluate(args);
        }
    }
};

void Arch::read_pdc(std::istream &in)
{
    std::string buf(std::istreambuf_iterator<char>(in), {});
    PDCParser(buf, getCtx())();
}

NEXTPNR_NAMESPACE_END
<commit_msg>nexus: Add support for get_pins PDC command<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2020  David Shah <dave@ds0.me>
 *
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "log.h"
#include "nextpnr.h"

#include <iterator>

NEXTPNR_NAMESPACE_BEGIN

struct TCLEntity
{
    enum EntityType
    {
        ENTITY_CELL,
        ENTITY_PORT,
        ENTITY_NET,
        ENTITY_PIN,
    } type;
    IdString name;
    IdString pin; // for cell pins only

    TCLEntity(EntityType type, IdString name) : type(type), name(name) {}
    TCLEntity(EntityType type, IdString name, IdString pin) : type(type), name(name), pin(pin) {}

    const std::string &to_string(Context *ctx) { return name.str(ctx); }

    CellInfo *get_cell(Context *ctx) const
    {
        if (type != ENTITY_CELL)
            return nullptr;
        return ctx->cells.at(name).get();
    }

    PortInfo *get_port(Context *ctx) const
    {
        if (type != ENTITY_PORT)
            return nullptr;
        return &ctx->ports.at(name);
    }

    NetInfo *get_net(Context *ctx) const
    {
        if (type == ENTITY_PIN) {
            CellInfo *cell = nullptr;
            if (ctx->cells.count(name)) {
                cell = ctx->cells.at(name).get();
            } else {
                const std::string &n = name.str(ctx);
                auto pos = n.rfind('.');
                if (pos == std::string::npos)
                    return nullptr;
                // remove one hierarchy layer due to Radiant weirdness around PLLs etc
                IdString stripped_name = ctx->id(n.substr(0, pos));
                if (!ctx->cells.count(stripped_name))
                    return nullptr;
                cell = ctx->cells.at(stripped_name).get();
            }
            if (!cell->ports.count(pin))
                return nullptr;
            return cell->ports.at(pin).net;
        } else if (type == ENTITY_NET) {
            return ctx->nets.at(name).get();
        } else {
            return nullptr;
        }
    }
};

struct TCLValue
{
    TCLValue(const std::string &s) : is_string(true), str(s){};
    TCLValue(const std::vector<TCLEntity> &l) : is_string(false), list(l){};

    bool is_string;
    std::string str;             // simple string value
    std::vector<TCLEntity> list; // list of entities
};

struct PDCParser
{
    std::string buf;
    int pos = 0;
    int lineno = 1;
    Context *ctx;

    PDCParser(const std::string &buf, Context *ctx) : buf(buf), ctx(ctx){};

    inline bool eof() const { return pos == int(buf.size()); }

    inline char peek() const { return buf.at(pos); }

    inline char get()
    {
        char c = buf.at(pos++);
        if (c == '\n')
            ++lineno;
        return c;
    }

    std::string get(int n)
    {
        std::string s = buf.substr(pos, n);
        pos += n;
        return s;
    }

    // If next char matches c, take it from the stream and return true
    bool check_get(char c)
    {
        if (peek() == c) {
            get();
            return true;
        } else {
            return false;
        }
    }

    // If next char matches any in chars, take it from the stream and return true
    bool check_get_any(const std::string &chrs)
    {
        char c = peek();
        if (chrs.find(c) != std::string::npos) {
            get();
            return true;
        } else {
            return false;
        }
    }

    inline void skip_blank(bool nl = false)
    {
        while (!eof() && check_get_any(nl ? " \t\n\r" : " \t"))
            ;
    }

    // Return true if end of line (or file)
    inline bool skip_check_eol()
    {
        skip_blank(false);
        if (eof())
            return true;
        char c = peek();
        // Comments count as end of line
        if (c == '#') {
            get();
            while (!eof() && peek() != '\n' && peek() != '\r')
                get();
            return true;
        }
        if (c == ';') {
            // Forced end of line
            get();
            return true;
        }
        return (c == '\n' || c == '\r');
    }

    inline std::string get_str()
    {
        std::string s;
        skip_blank(false);
        if (eof())
            return "";

        bool in_quotes = false, in_braces = false, escaped = false;

        char c = get();

        if (c == '"')
            in_quotes = true;
        else if (c == '{')
            in_braces = true;
        else
            s += c;

        while (true) {
            char c = peek();
            if (!in_quotes && !in_braces && !escaped && (std::isblank(c) || c == ']')) {
                break;
            }
            get();
            if (escaped) {
                s += c;
                escaped = false;
            } else if ((in_quotes && c == '"') || (in_braces && c == '}')) {
                break;
            } else if (c == '\\') {
                escaped = true;
            } else {
                s += c;
            }
        }

        return s;
    }

    TCLValue evaluate(const std::vector<TCLValue> &arguments)
    {
        NPNR_ASSERT(!arguments.empty());
        auto &arg0 = arguments.at(0);
        NPNR_ASSERT(arg0.is_string);
        const std::string &cmd = arg0.str;
        if (cmd == "get_ports")
            return cmd_get_ports(arguments);
        else if (cmd == "get_cells")
            return cmd_get_cells(arguments);
        else if (cmd == "get_nets")
            return cmd_get_nets(arguments);
        else if (cmd == "get_pins")
            return cmd_get_pins(arguments);
        else if (cmd == "create_clock")
            return cmd_create_clock(arguments);
        else if (cmd == "ldc_set_location")
            return cmd_ldc_set_location(arguments);
        else if (cmd == "ldc_set_port")
            return cmd_ldc_set_port(arguments);
        else if (cmd == "ldc_set_sysconfig" || cmd == "get_nets" || cmd == "create_clock") {
            log_warning("%s is not yet supported!\n", cmd.c_str());
            return TCLValue("");
        } else
            log_error("Unsupported PDC command '%s'\n", cmd.c_str());
    }

    std::vector<TCLValue> get_arguments()
    {
        std::vector<TCLValue> args;
        while (!skip_check_eol()) {
            if (check_get('[')) {
                // Start of a sub-expression
                auto result = evaluate(get_arguments());
                NPNR_ASSERT(check_get(']'));
                args.push_back(result);
            } else if (peek() == ']') {
                break;
            } else {
                args.push_back(get_str());
            }
        }
        skip_blank(true);
        return args;
    }

    TCLValue cmd_get_nets(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> nets;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_nets expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_nets (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->nets.count(id) || ctx->net_aliases.count(id))
                nets.emplace_back(TCLEntity::ENTITY_NET, ctx->net_aliases.count(id) ? ctx->net_aliases.at(id) : id);
            else
                log_warning("get_nets argument '%s' matched no objects.\n", s.c_str());
        }
        return nets;
    }

    TCLValue cmd_get_ports(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> ports;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_ports expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_ports (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->ports.count(id))
                ports.emplace_back(TCLEntity::ENTITY_PORT, id);
        }
        return ports;
    }

    TCLValue cmd_get_cells(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> cells;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_cells expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_cells (line %d)\n", s.c_str(), lineno);
            IdString id = ctx->id(s);
            if (ctx->cells.count(id))
                cells.emplace_back(TCLEntity::ENTITY_CELL, id);
        }
        return cells;
    }

    TCLValue cmd_get_pins(const std::vector<TCLValue> &arguments)
    {
        std::vector<TCLEntity> pins;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (!arg.is_string)
                log_error("get_pins expected string arguments (line %d)\n", lineno);
            std::string s = arg.str;
            if (s.at(0) == '-')
                log_error("unsupported argument '%s' to get_pins (line %d)\n", s.c_str(), lineno);
            auto pos = s.rfind('/');
            if (pos == std::string::npos)
                log_error("expected / in cell pin name '%s' (line %d)\n", s.c_str(), lineno);
            pins.emplace_back(TCLEntity::ENTITY_PIN, ctx->id(s.substr(0, pos)), ctx->id(s.substr(pos + 1)));
            if (pins.back().get_net(ctx) == nullptr) {
                log_warning("cell pin '%s' not found\n", s.c_str());
                pins.pop_back();
            }
        }
        return pins;
    }

    TCLValue cmd_create_clock(const std::vector<TCLValue> &arguments)
    {
        float period = 10;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-period") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -period (line %d)\n", lineno);
                    try {
                        period = std::stof(val.str);
                    } catch (std::exception &e) {
                        log_error("invalid argument '%s' to -period (line %d)\n", val.str.c_str(), lineno);
                    }
                } else if (s == "-name") {
                    i++;
                } else {
                    log_error("unsupported argument '%s' to create_clock\n", s.c_str());
                }
            } else {
                for (const auto &ety : arg.list) {
                    NetInfo *net = nullptr;
                    if (ety.type == TCLEntity::ENTITY_PIN)
                        net = ety.get_net(ctx);
                    else if (ety.type == TCLEntity::ENTITY_NET)
                        net = ctx->nets.at(ety.name).get();
                    else if (ety.type == TCLEntity::ENTITY_PORT)
                        net = ctx->ports.at(ety.name).net;
                    else
                        log_error("create_clock applies only to cells, cell pins, or IO ports (line %d)\n", lineno);
                    ctx->addClock(net->name, 1000.0f / period);
                }
            }
        }
        return std::string{};
    }

    TCLValue cmd_ldc_set_location(const std::vector<TCLValue> &arguments)
    {
        std::string site;

        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-site") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -site (line %d)\n", lineno);
                    site = val.str;
                }
            } else {
                if (site.empty())
                    log_error("expecting -site before list of objects (line %d)\n", lineno);
                for (const auto &ety : arg.list) {
                    if (ety.type == TCLEntity::ENTITY_PORT)
                        ctx->io_attr[ety.name][id_LOC] = site;
                    else if (ety.type == TCLEntity::ENTITY_CELL)
                        ctx->cells[ety.name]->attrs[id_LOC] = site;
                    else
                        log_error("ldc_set_location applies only to cells or IO ports (line %d)\n", lineno);
                }
            }
        }
        return std::string{};
    }

    TCLValue cmd_ldc_set_port(const std::vector<TCLValue> &arguments)
    {
        std::unordered_map<IdString, Property> args;
        for (int i = 1; i < int(arguments.size()); i++) {
            auto &arg = arguments.at(i);
            if (arg.is_string) {
                std::string s = arg.str;
                if (s == "-iobuf") {
                    i++;
                    auto &val = arguments.at(i);
                    if (!val.is_string)
                        log_error("expecting string argument to -iobuf (line %d)\n", lineno);
                    std::stringstream ss(val.str);
                    std::string kv;
                    while (ss >> kv) {
                        auto eqp = kv.find('=');
                        if (eqp == std::string::npos)
                            log_error("expected key-value pair separated by '=' (line %d)", lineno);
                        std::string k = kv.substr(0, eqp), v = kv.substr(eqp + 1);
                        args[ctx->id(k)] = v;
                    }
                } else {
                    log_error("unexpected argument '%s' to ldc_set_port (line %d)\n", s.c_str(), lineno);
                }
            } else {
                for (const auto &ety : arg.list) {
                    if (ety.type == TCLEntity::ENTITY_PORT)
                        for (const auto &kv : args)
                            ctx->io_attr[ety.name][kv.first] = kv.second;
                    else
                        log_error("ldc_set_port applies only to IO ports (line %d)\n", lineno);
                }
            }
        }
        return std::string{};
    }

    void operator()()
    {
        while (!eof()) {
            skip_blank(true);
            auto args = get_arguments();
            if (args.empty())
                continue;
            evaluate(args);
        }
    }
};

void Arch::read_pdc(std::istream &in)
{
    std::string buf(std::istreambuf_iterator<char>(in), {});
    PDCParser(buf, getCtx())();
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRA;NTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/View>
#include <osg/Notify>
#include <osg/TexEnv>
#include <osg/DeleteHandler>

using namespace osg;

View::View():
    Object(true)
{
    // OSG_NOTICE<<"Constructing osg::View"<<std::endl;

    setLightingMode(HEADLIGHT);

    _camera = new osg::Camera;
    _camera->setView(this);

    double height = osg::DisplaySettings::instance()->getScreenHeight();
    double width = osg::DisplaySettings::instance()->getScreenWidth();
    double distance = osg::DisplaySettings::instance()->getScreenDistance();
    double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0);

    _camera->setProjectionMatrixAsPerspective( vfov, width/height, 1.0f,10000.0f);

    _camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f));

    osg::StateSet* stateset = _camera->getOrCreateStateSet();
    stateset->setGlobalDefaults();
}

View::View(const osg::View& view, const osg::CopyOp& copyop):
    Object(view,copyop),
    _lightingMode(view._lightingMode),
    _light(view._light),
    _camera(view._camera),
    _slaves(view._slaves)
{
}

View::~View()
{
    OSG_INFO<<"Destructing osg::View"<<std::endl;

    if (_camera.valid())
    {
        _camera->setView(0);
        _camera->setCullCallback(0);
    }

    // detach the cameras from this View to prevent dangling pointers
    for(Slaves::iterator itr = _slaves.begin();
        itr != _slaves.end();
        ++itr)
    {
        Slave& cd = *itr;
        cd._camera->setView(0);
        cd._camera->setCullCallback(0);
    }

    _camera = 0;
    _slaves.clear();
    _light = 0;

#if 0
    if (osg::Referenced::getDeleteHandler())
    {
        // osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
        osg::Referenced::getDeleteHandler()->flushAll();
    }
#endif

    OSG_INFO<<"Done destructing osg::View"<<std::endl;
}

void View::take(osg::View& rhs)
{
    // copy across the contents first
    _lightingMode = rhs._lightingMode;
    _light = rhs._light;
    _camera = rhs._camera;
    _slaves = rhs._slaves;

    // update the cameras so they all now see this View as their parent View
    if (_camera.valid()) _camera->setView(this);

    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        if (_slaves[i]._camera.valid()) _slaves[i]._camera->setView(this);
    }

    // then clear the passing in view.
    rhs._light = 0;
    rhs._camera = 0;
    rhs._slaves.clear();
}

void View::setLightingMode(LightingMode lightingMode)
{
    _lightingMode = lightingMode;
    if (_lightingMode != NO_LIGHT && !_light)
    {
        _light = new osg::Light;
        _light->setThreadSafeRefUnref(true);
        _light->setLightNum(0);
        _light->setAmbient(Vec4(0.00f,0.0f,0.00f,1.0f));
        _light->setDiffuse(Vec4(0.8f,0.8f,0.8f,1.0f));
        _light->setSpecular(Vec4(1.0f,1.0f,1.0f,1.0f));
    }
}

void View::setCamera(osg::Camera* camera)
{
    if (_camera.valid()) _camera->setView(0);

    _camera = camera;

    if (_camera.valid())
    {
        _camera->setView(this);
        _camera->setRenderer(createRenderer(camera));
    }
}

void View::updateSlaves()
{
    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        Slave& slave = _slaves[i];
        slave.updateSlave(*this);
    }
}

void View::Slave::updateSlaveImplementation(View& view)
{
    if (!view.getCamera()) return;

    if (_camera->getReferenceFrame()==osg::Transform::RELATIVE_RF)
    {
        _camera->setProjectionMatrix(view.getCamera()->getProjectionMatrix() * _projectionOffset);
        _camera->setViewMatrix(view.getCamera()->getViewMatrix() * _viewOffset);
    }

    _camera->inheritCullSettings(*(view.getCamera()), _camera->getInheritanceMask());
}

bool View::addSlave(osg::Camera* camera, const osg::Matrix& projectionOffset, const osg::Matrix& viewOffset, bool useMastersSceneData)
{
    if (!camera) return false;

    camera->setView(this);

    unsigned int i = _slaves.size();

    if (useMastersSceneData)
    {
        camera->removeChildren(0,camera->getNumChildren());

        if (_camera.valid())
        {
            for(unsigned int i=0; i<_camera->getNumChildren(); ++i)
            {
                camera->addChild(_camera->getChild(i));
            }
        }
    }

    _slaves.push_back(Slave(camera, projectionOffset, viewOffset, useMastersSceneData));

    _slaves[i].updateSlave(*this);

    camera->setRenderer(createRenderer(camera));

    return true;
}

bool View::removeSlave(unsigned int pos)
{
    if (pos >= _slaves.size()) return false;

    _slaves[pos]._camera->setView(0);
    _slaves[pos]._camera->setCullCallback(0);

    _slaves.erase(_slaves.begin()+pos);

    return true;
}

View::Slave * View::findSlaveForCamera(osg::Camera* camera)
{
    unsigned int i = findSlaveIndexForCamera(camera);

    if (i >= getNumSlaves()) return (NULL);

    return &(_slaves[i]);
}

unsigned int View::findSlaveIndexForCamera(osg::Camera* camera) const
{
    if (_camera == camera) return _slaves.size();

    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        if (_slaves[i]._camera == camera) return (i);
    }

    return _slaves.size();
}

<commit_msg>Fixed shadows warning<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRA;NTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/View>
#include <osg/Notify>
#include <osg/TexEnv>
#include <osg/DeleteHandler>

using namespace osg;

View::View():
    Object(true)
{
    // OSG_NOTICE<<"Constructing osg::View"<<std::endl;

    setLightingMode(HEADLIGHT);

    _camera = new osg::Camera;
    _camera->setView(this);

    double height = osg::DisplaySettings::instance()->getScreenHeight();
    double width = osg::DisplaySettings::instance()->getScreenWidth();
    double distance = osg::DisplaySettings::instance()->getScreenDistance();
    double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0);

    _camera->setProjectionMatrixAsPerspective( vfov, width/height, 1.0f,10000.0f);

    _camera->setClearColor(osg::Vec4f(0.2f, 0.2f, 0.4f, 1.0f));

    osg::StateSet* stateset = _camera->getOrCreateStateSet();
    stateset->setGlobalDefaults();
}

View::View(const osg::View& view, const osg::CopyOp& copyop):
    Object(view,copyop),
    _lightingMode(view._lightingMode),
    _light(view._light),
    _camera(view._camera),
    _slaves(view._slaves)
{
}

View::~View()
{
    OSG_INFO<<"Destructing osg::View"<<std::endl;

    if (_camera.valid())
    {
        _camera->setView(0);
        _camera->setCullCallback(0);
    }

    // detach the cameras from this View to prevent dangling pointers
    for(Slaves::iterator itr = _slaves.begin();
        itr != _slaves.end();
        ++itr)
    {
        Slave& cd = *itr;
        cd._camera->setView(0);
        cd._camera->setCullCallback(0);
    }

    _camera = 0;
    _slaves.clear();
    _light = 0;

#if 0
    if (osg::Referenced::getDeleteHandler())
    {
        // osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
        osg::Referenced::getDeleteHandler()->flushAll();
    }
#endif

    OSG_INFO<<"Done destructing osg::View"<<std::endl;
}

void View::take(osg::View& rhs)
{
    // copy across the contents first
    _lightingMode = rhs._lightingMode;
    _light = rhs._light;
    _camera = rhs._camera;
    _slaves = rhs._slaves;

    // update the cameras so they all now see this View as their parent View
    if (_camera.valid()) _camera->setView(this);

    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        if (_slaves[i]._camera.valid()) _slaves[i]._camera->setView(this);
    }

    // then clear the passing in view.
    rhs._light = 0;
    rhs._camera = 0;
    rhs._slaves.clear();
}

void View::setLightingMode(LightingMode lightingMode)
{
    _lightingMode = lightingMode;
    if (_lightingMode != NO_LIGHT && !_light)
    {
        _light = new osg::Light;
        _light->setThreadSafeRefUnref(true);
        _light->setLightNum(0);
        _light->setAmbient(Vec4(0.00f,0.0f,0.00f,1.0f));
        _light->setDiffuse(Vec4(0.8f,0.8f,0.8f,1.0f));
        _light->setSpecular(Vec4(1.0f,1.0f,1.0f,1.0f));
    }
}

void View::setCamera(osg::Camera* camera)
{
    if (_camera.valid()) _camera->setView(0);

    _camera = camera;

    if (_camera.valid())
    {
        _camera->setView(this);
        _camera->setRenderer(createRenderer(camera));
    }
}

void View::updateSlaves()
{
    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        Slave& slave = _slaves[i];
        slave.updateSlave(*this);
    }
}

void View::Slave::updateSlaveImplementation(View& view)
{
    if (!view.getCamera()) return;

    if (_camera->getReferenceFrame()==osg::Transform::RELATIVE_RF)
    {
        _camera->setProjectionMatrix(view.getCamera()->getProjectionMatrix() * _projectionOffset);
        _camera->setViewMatrix(view.getCamera()->getViewMatrix() * _viewOffset);
    }

    _camera->inheritCullSettings(*(view.getCamera()), _camera->getInheritanceMask());
}

bool View::addSlave(osg::Camera* camera, const osg::Matrix& projectionOffset, const osg::Matrix& viewOffset, bool useMastersSceneData)
{
    if (!camera) return false;

    camera->setView(this);

    if (useMastersSceneData)
    {
        camera->removeChildren(0,camera->getNumChildren());

        if (_camera.valid())
        {
            for(unsigned int i=0; i<_camera->getNumChildren(); ++i)
            {
                camera->addChild(_camera->getChild(i));
            }
        }
    }

    unsigned int i = _slaves.size();

    _slaves.push_back(Slave(camera, projectionOffset, viewOffset, useMastersSceneData));
    _slaves[i].updateSlave(*this);

    camera->setRenderer(createRenderer(camera));

    return true;
}

bool View::removeSlave(unsigned int pos)
{
    if (pos >= _slaves.size()) return false;

    _slaves[pos]._camera->setView(0);
    _slaves[pos]._camera->setCullCallback(0);

    _slaves.erase(_slaves.begin()+pos);

    return true;
}

View::Slave * View::findSlaveForCamera(osg::Camera* camera)
{
    unsigned int i = findSlaveIndexForCamera(camera);

    if (i >= getNumSlaves()) return (NULL);

    return &(_slaves[i]);
}

unsigned int View::findSlaveIndexForCamera(osg::Camera* camera) const
{
    if (_camera == camera) return _slaves.size();

    for(unsigned int i=0; i<_slaves.size(); ++i)
    {
        if (_slaves[i]._camera == camera) return (i);
    }

    return _slaves.size();
}

<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  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 copyright holder(s) 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.
 *
 * $Id$
 *
 */

/**

@b pcd_concatenate_points exemplifies how to concatenate the points of two PointClouds having the same fields.

**/

#include <iostream>
#include <pcl/console/time.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

Eigen::Vector4f    translation;
Eigen::Quaternionf orientation;

////////////////////////////////////////////////////////////////////////////////
/** \brief Parse command line arguments for file names.
  * Returns: a vector with file names indices.
  * \param argc
  * \param argv
  * \param extension
  */
std::vector<int>
parseFileExtensionArgument (int argc, char** argv, std::string extension)
{
  std::vector<int> indices;
  for (int i = 1; i < argc; ++i)
  {
    std::string fname = std::string (argv[i]);

    // Needs to be at least 4: .ext
    if (fname.size () <= 4)
      continue;

    // For being case insensitive
    std::transform (fname.begin (), fname.end (), fname.begin (), tolower);
    std::transform (extension.begin (), extension.end (), extension.begin (), tolower);

    // Check if found
    std::string::size_type it;
    if ((it = fname.find (extension)) != std::string::npos)
    {
      // Additional check: we want to be able to differentiate between .p and .png
      if ((extension.size () - (fname.size () - it)) == 0)
        indices.push_back (i);
    }
  }
  return (indices);
}

bool
loadCloud (const std::string &filename, sensor_msgs::PointCloud2 &cloud)
{
  using namespace pcl::console;
  TicToc tt;
  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (pcl::io::loadPCDFile (filename, cloud, translation, orientation) < 0)
    return (false);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
saveCloud (const std::string &filename, const sensor_msgs::PointCloud2 &output)
{
  using namespace pcl::console;
  TicToc tt;
  tt.tic ();

  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::PCDWriter w;
  w.writeBinaryCompressed (filename, output, translation, orientation);

  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", output.width * output.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
  if (argc < 2)
  {
    std::cerr << "Syntax is: " << argv[0] << " <filename 1..N.pcd>" << std::endl;
    std::cerr << "Result will be saved to output.pcd" << std::endl;
    return (-1);
  }

  std::vector<int> file_indices = parseFileExtensionArgument (argc, argv, ".pcd");

  //pcl::PointCloud<pcl::PointXYZ> cloud_all;
  sensor_msgs::PointCloud2 cloud_all;
  for (size_t i = 0; i < file_indices.size (); ++i)
  {
    // Load the Point Cloud
    sensor_msgs::PointCloud2 cloud;
    loadCloud (argv[file_indices[i]], cloud);
    //pcl::PointCloud<pcl::PointXYZ> cloud;
    //pcl::io::loadPCDFile (argv[file_indices[i]], cloud);
    //cloud_all += cloud;
    pcl::concatenatePointCloud (cloud_all, cloud, cloud_all);
  }

  saveCloud ("output.pcd", cloud_all);

  return (0);
}
/* ]--- */
<commit_msg>added extra info<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  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 copyright holder(s) 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.
 *
 * $Id$
 *
 */

/**

@b pcd_concatenate_points exemplifies how to concatenate the points of two PointClouds having the same fields.

**/

#include <iostream>
#include <pcl/console/time.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

Eigen::Vector4f    translation;
Eigen::Quaternionf orientation;

////////////////////////////////////////////////////////////////////////////////
/** \brief Parse command line arguments for file names.
  * Returns: a vector with file names indices.
  * \param argc
  * \param argv
  * \param extension
  */
std::vector<int>
parseFileExtensionArgument (int argc, char** argv, std::string extension)
{
  std::vector<int> indices;
  for (int i = 1; i < argc; ++i)
  {
    std::string fname = std::string (argv[i]);

    // Needs to be at least 4: .ext
    if (fname.size () <= 4)
      continue;

    // For being case insensitive
    std::transform (fname.begin (), fname.end (), fname.begin (), tolower);
    std::transform (extension.begin (), extension.end (), extension.begin (), tolower);

    // Check if found
    std::string::size_type it;
    if ((it = fname.find (extension)) != std::string::npos)
    {
      // Additional check: we want to be able to differentiate between .p and .png
      if ((extension.size () - (fname.size () - it)) == 0)
        indices.push_back (i);
    }
  }
  return (indices);
}

bool
loadCloud (const std::string &filename, sensor_msgs::PointCloud2 &cloud)
{
  using namespace pcl::console;
  TicToc tt;
  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (pcl::io::loadPCDFile (filename, cloud, translation, orientation) < 0)
    return (false);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
saveCloud (const std::string &filename, const sensor_msgs::PointCloud2 &output)
{
  using namespace pcl::console;
  TicToc tt;
  tt.tic ();

  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::PCDWriter w;
  w.writeBinary (filename, output, translation, orientation);

  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", output.width * output.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
  if (argc < 2)
  {
    std::cerr << "Syntax is: " << argv[0] << " <filename 1..N.pcd>" << std::endl;
    std::cerr << "Result will be saved to output.pcd" << std::endl;
    return (-1);
  }

  std::vector<int> file_indices = parseFileExtensionArgument (argc, argv, ".pcd");

  //pcl::PointCloud<pcl::PointXYZ> cloud_all;
  sensor_msgs::PointCloud2 cloud_all;
  for (size_t i = 0; i < file_indices.size (); ++i)
  {
    // Load the Point Cloud
    sensor_msgs::PointCloud2 cloud;
    loadCloud (argv[file_indices[i]], cloud);
    //pcl::PointCloud<pcl::PointXYZ> cloud;
    //pcl::io::loadPCDFile (argv[file_indices[i]], cloud);
    //cloud_all += cloud;
    pcl::concatenatePointCloud (cloud_all, cloud, cloud_all);
    PCL_INFO ("Total number of points so far: %u. Total data size: %zu bytes.\n", cloud_all.width * cloud_all.height, cloud_all.data.size ());
  }

  saveCloud ("output.pcd", cloud_all);

  return (0);
}
/* ]--- */
<|endoftext|>


<commit_before>#include "ArgHandler.h"

ArgHandler::ArgHandler() {
	// handle defaults in the parse(..) and verify(..) functions
}
void ArgHandler::parse(int argc, char** argv) {
	desc.add_options()

    /*
    --dsl on
    --dsb on
    --friderived on

    --nfeed on
    --avlnflg on
    --baseline on
    */
    ("env", boost::program_options::value<string>(&env)->default_value("on"),
     "Turn the environmental module on or off."
    )
    ("bgc", boost::program_options::value<string>(&bgc)->default_value("on"),
     "Turn the biogeochemical module on or off."
    )
    ("dvm", boost::program_options::value<string>(&dvm)->default_value("on"),
     "Turn the dynamic vegetation module on or off."
    )
    ("calibrationmode", boost::program_options::value<string>(&calibrationmode)->default_value("off"),
     "(NOT IMPLEMENTED) whether or not the calibration module is on...? "
     "list of strings for modules to calibrate?"
    )
    ("loglevel,l", boost::program_options::value<string>(&loglevel)->default_value("trace"),
     "the level above which all log messages will be printed. Here are the "
     "choices: trace, debug, info, warning, error, fatal."
    )
		("mode,m", boost::program_options::value<string>(&mode)->default_value("siterun"),"change mode between siterun and regnrun")
		("control-file,f", boost::program_options::value<string>(&ctrlfile)->default_value("config/controlfile_site.txt"), "choose a control file to use")
		("cohort-id,c", boost::program_options::value<string>(&chtid)->default_value("1"), "choose a specific cohort to run")
		("space-time-config,s", boost::program_options::value<string>(), "choose spatial or temporal running mode")
		("help,h", "produces helps message, then quits")
		("version,v", "(NOT IMPLEMENTED)show the version information")
		("debug,d", "(NOT IMPLEMENTED) enable debug mode")
	;

	boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), varmap);
	boost::program_options::notify(varmap);

  if (varmap.count("env")) {
    env = varmap["env"].as<string>();
  }
  if (varmap.count("bgc")) {
    bgc = varmap["bgc"].as<string>();
  }
  if (varmap.count("dvm")) {
    dvm = varmap["dvm"].as<string>();
  }

	if (varmap.count("cohort-id")) {
		chtid = varmap["cohort-id"].as<string>();
	}

	if (varmap.count("space-time-config")) {
		regrunmode = varmap["space-time-config"].as<string>();
	}

	if (varmap.count("help")) {
		help = true;
	}

	if (varmap.count("version")) {
		version = true;
	}

	if (varmap.count("debug")) {
		debug = true;
	}
}

void ArgHandler::verify() {
  // The regional "run mode"...loop order??
  std::cout << "Verification reuimentary - needs more programming help!\n";
  if (mode.compare("regnrun") == 0) {
    if ( (regrunmode.compare("regner1") == 0) ||
        (regrunmode.compare("regner2") == 0) ) {
      // pass, all ok
    } else {
      std::cout << "Invalid option (regrunmode). Quitting.\n";
      exit(-1);
    }
  }
}

string ArgHandler::getEnv() const {
  return env;
}
string ArgHandler::getBgc() const {
  return bgc;
}
string ArgHandler::getDvm() const {
  return dvm;
}
string ArgHandler::getCalibrationMode(){
  return calibrationmode;
}
string ArgHandler::getLogLevel(){
	return loglevel;
}
string ArgHandler::getMode(){
	return mode;
}

string ArgHandler::getCtrlfile(){
	return ctrlfile;
}

string ArgHandler::getChtid(){
	return chtid;
}

string ArgHandler::getRegrunmode(){
	return regrunmode;
}

void ArgHandler::showHelp(){
/**
 * Print out command help
 */
	std::cout << desc << std::endl;
}
<commit_msg>comment out command line options for module control.<commit_after>#include "ArgHandler.h"

ArgHandler::ArgHandler() {
	// handle defaults in the parse(..) and verify(..) functions
}
void ArgHandler::parse(int argc, char** argv) {
	desc.add_options()

    /*
    --env [ on | off ]
    --bgc [ on | off ]
    --dvm [ on | off ]
    --dsl [ on | off ]
    --dsb [ on | off ]
    --friderived  [ on | off ]
    */
    // NOT IMPLEMENTED YET - need to sort out some issues
    // ("env", boost::program_options::value<string>(&env)->default_value("on"),
    //   "Turn the environmental module on or off."
    // )
    // ("bgc", boost::program_options::value<string>(&bgc)->default_value("on"),
    //   "Turn the biogeochemical module on or off."
    // )
    // ("dvm", boost::program_options::value<string>(&dvm)->default_value("on"),
    //   "Turn the dynamic vegetation module on or off."
    // )

    ("calibrationmode", boost::program_options::value<string>(&calibrationmode)->default_value("off"),
     "(NOT IMPLEMENTED) whether or not the calibration module is on...? "
     "list of strings for modules to calibrate?"
    )
    ("loglevel,l", boost::program_options::value<string>(&loglevel)->default_value("trace"),
     "the level above which all log messages will be printed. Here are the "
     "choices: trace, debug, info, warning, error, fatal."
    )
		("mode,m", boost::program_options::value<string>(&mode)->default_value("siterun"),"change mode between siterun and regnrun")
		("control-file,f", boost::program_options::value<string>(&ctrlfile)->default_value("config/controlfile_site.txt"), "choose a control file to use")
		("cohort-id,c", boost::program_options::value<string>(&chtid)->default_value("1"), "choose a specific cohort to run")
		("space-time-config,s", boost::program_options::value<string>(), "choose spatial or temporal running mode")
		("help,h", "produces helps message, then quits")
		("version,v", "(NOT IMPLEMENTED)show the version information")
		("debug,d", "(NOT IMPLEMENTED) enable debug mode")
	;

	boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), varmap);
	boost::program_options::notify(varmap);

  if (varmap.count("env")) {
    env = varmap["env"].as<string>();
  }
  if (varmap.count("bgc")) {
    bgc = varmap["bgc"].as<string>();
  }
  if (varmap.count("dvm")) {
    dvm = varmap["dvm"].as<string>();
  }

	if (varmap.count("cohort-id")) {
		chtid = varmap["cohort-id"].as<string>();
	}

	if (varmap.count("space-time-config")) {
		regrunmode = varmap["space-time-config"].as<string>();
	}

	if (varmap.count("help")) {
		help = true;
	}

	if (varmap.count("version")) {
		version = true;
	}

	if (varmap.count("debug")) {
		debug = true;
	}
}

void ArgHandler::verify() {
  // The regional "run mode"...loop order??
  std::cout << "Verification reuimentary - needs more programming help!\n";
  if (mode.compare("regnrun") == 0) {
    if ( (regrunmode.compare("regner1") == 0) ||
        (regrunmode.compare("regner2") == 0) ) {
      // pass, all ok
    } else {
      std::cout << "Invalid option (regrunmode). Quitting.\n";
      exit(-1);
    }
  }
}

string ArgHandler::getEnv() const {
  return env;
}
string ArgHandler::getBgc() const {
  return bgc;
}
string ArgHandler::getDvm() const {
  return dvm;
}
string ArgHandler::getCalibrationMode(){
  return calibrationmode;
}
string ArgHandler::getLogLevel(){
	return loglevel;
}
string ArgHandler::getMode(){
	return mode;
}

string ArgHandler::getCtrlfile(){
	return ctrlfile;
}

string ArgHandler::getChtid(){
	return chtid;
}

string ArgHandler::getRegrunmode(){
	return regrunmode;
}

void ArgHandler::showHelp(){
/**
 * Print out command help
 */
	std::cout << desc << std::endl;
}
<|endoftext|>


<commit_before>/*
    Authors: Darya Filippova, Geet Duggal, Rob Patro
    dfilippo | geet | robp @cs.cmu.edu
*/

#include <limits>
#include <boost/heap/binomial_heap.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include "ArmatusDAG.hpp"

ArmatusDAG::ArmatusDAG(ArmatusParams& p) :
	subProbs(SubProbsVec(p.n)),
    edgeWeights(EdgeWeightsVec(p.n, vector<double>())) {
	params = &p;
}

void ArmatusDAG::build() {
	// Since building the DAG visits everything in the same order as computing
	// a single optimial solution, I've had this function also fill out the
	// necessary information to obtain a backtrace of the opt. sln.
	subProbs[0].topK.push_back({std::numeric_limits<size_t>::max(), 0, 0.0});
	// What's the right condition here?
	// subProbs[1].topK.push_back({0, 0, std::max(q(0,1), 0.0)});

    for (size_t l : boost::irange(size_t{1}, params->n)) {
        // was this
  	    // edgeWeights[l].resize(l-1);
        // now this
  	    edgeWeights[l].resize(l);
  	    size_t chosenEdge = 0;
  	    double bestScore = 0.0;
  	    for (size_t k : boost::irange(size_t{0}, l)) {
  	    	// The last domain is [k,l]
  	    	double edgeWeight = std::max(q(k, l), 0.0);
            edgeWeights[l][k] = edgeWeight;
            double totalScore = edgeWeight;
            bool isDomain = edgeWeight > 0.0;
            bool isPrevDomain = (k == 0) ? true : false;
            if (k > 0) {
                double prevDomainScore = subProbs[k-1].topK[0].score;
                isPrevDomain = prevDomainScore > 0.0;
                // The score of this solution is the benefit we get from traversing
                // the edge + the best score available at the child
                totalScore += prevDomainScore;
             }
             if (isDomain or isPrevDomain) {
                 if (totalScore > bestScore) {
                     bestScore = totalScore;
                     chosenEdge = k;
                 }
            }
  	    }

  	    // Put our best solution on the stack.
  	    subProbs[l].topK.push_back({chosenEdge, 0, bestScore});
    }
}

double ArmatusDAG::s(size_t k, size_t l) {
	size_t d = l-k+1;
    return params->sums(k, l)/ std::pow(static_cast<double>(d),params->gamma);
}

double ArmatusDAG::q(size_t k, size_t l) {
	size_t d = l-k+1;
	return (s(k, l) - params->mu[d]);
}

/**
*  This interface is *wrong* but I wanted to sketch the
*  basic algo.
**/
void ArmatusDAG::computeTopK(uint32_t k) {
	for (size_t l : boost::irange(size_t{1}, params->n)) {
		std::function<bool (const BackPointer&, const BackPointer&)> BackPointerComparator = [l, this] (const BackPointer& x, const BackPointer& y) -> bool {
            auto scoreX = this->edgeWeights[l][x.edge];
            if (x.edge > 0) { scoreX += this->subProbs[x.edge-1].topK[x.childSolution].score; }
            auto scoreY = this->edgeWeights[l][y.edge];
            if (y.edge > 0) { scoreY += this->subProbs[y.edge-1].topK[y.childSolution].score; }

			return scoreX < scoreY;
		};

		boost::heap::binomial_heap<BackPointer,
		                           boost::heap::compare<decltype(BackPointerComparator)>> pq(BackPointerComparator);
		for (size_t j : boost::irange(size_t{0}, l)) {
            if (j > 0) {
                size_t i = j - 1;
                bool isDomain = edgeWeights[l][j] > 0.0;
                bool prevIsDomain = (subProbs[i].topK.size() > 0 and edgeWeights[i].size() > 0) ? edgeWeights[i][subProbs[i].topK[0].edge] > 0 : true;
                if (j == 1) { prevIsDomain = false; }

                if (isDomain or prevIsDomain) {
                    double score = edgeWeights[l][j] + subProbs[i].topK[0].score;
                    pq.push({j, 0, score});
                }
            } else {
                double score = edgeWeights[l][0];
                pq.push({0, 0, score});
            }
		}

		while (subProbs[l].topK.size() < k and !pq.empty()) {
			auto bp = pq.top();
			pq.pop();
            size_t j = bp.edge;
            if (j > 0) {
                bool alreadyFound{false};
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
                size_t nextSlnIdx = bp.childSolution + 1;
                bool isDomain = edgeWeights[l][j] > 0.0;

                size_t i = j - 1;
                //std::cout << bp.edge << "\t" << subProbs.size() << endl;
                if (nextSlnIdx < subProbs[i].topK.size()) {
                    bool prevIsDomain = edgeWeights[i][subProbs[i].topK[nextSlnIdx].edge] > 0.0;
                    if (isDomain or prevIsDomain ) {
                        double score = edgeWeights[l][j] + subProbs[i].topK[nextSlnIdx].score;
                        pq.push({j, nextSlnIdx, score});
                    }
                }
            } else {
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
            }
		}
	}

	// size_t sln = 0;
	// while (sln < k and sln < subProbs[params->n-1].topK.size()) {
	// 	std::cerr << "solution " << sln << " has score " << subProbs[params->n-1].topK[sln].score << "\n";
	// 	++sln;
	// }
}

WeightedDomainEnsemble ArmatusDAG::extractTopK(uint32_t k) {

  const size_t INVALID = std::numeric_limits<size_t>::max();
  // We skip 0 since that was already extracted by viterbiPath
  uint32_t currSln{0};

  WeightedDomainEnsemble solutions{ DomainEnsemble(k, DomainSet()), Weights(k, 0.0) };
  auto root = params->n-1;
  auto topScore = subProbs[root].topK[0].score;
  auto scores = Weights(k, 0.0);

  while (currSln < k and currSln < subProbs[root].topK.size()) {
    auto currentScore = subProbs[root].topK[currSln].score;
    scores[currSln] = currentScore;
    auto& currentDomainSet = solutions.domainSets[currSln];
    solutions.weights[currSln] = currentScore / topScore;

    // Which solution to use at the child
    auto bp = currSln;
    int64_t end = params->n-1;
    bool prevWasDomain = true;
    bool done{false};
    Domain prevDomain(root, root);

    while (end > 0) { // and subProbs[end].topK[bp].edge != INVALID) {
      //std::cerr << "end: " << end << "\n";
      size_t begin = subProbs[end].topK[bp].edge;
      size_t start = begin;
//      if (subProbs[begin].topK[subProbs[end].topK[bp].childSolution].edge != INVALID)
//         start++;
      Domain d(start, end);
      if (d.score(*params) > 0.0){
         currentDomainSet.push_back(d);
         prevWasDomain = true;
      } else {
         //currentDomainSet.push_back(d);
        if (!prevWasDomain) {
                std::cerr << "WHAT: solution contained two adjacent non-domains; current domain is (" << start << ", " << end << ") prev domain was (" << prevDomain.start << ", " << prevDomain.end << ")\n";
        }
        prevWasDomain = false;
      }
      prevDomain = d;
      bp = subProbs[end].topK[bp].childSolution;
      end = begin-1;
   }

    ++currSln;
  }

  /**
   * consistency check all the extracted domains (for debug purposes only,
   * take this out for release / speed).
   */
  size_t c = 0;
  double eps = 1e-3;
  for (auto& ds : solutions.domainSets) {
    double score = 0.0;
    for (auto& d : ds) {
      score += d.score(*params);
    }
    if (std::abs(score - scores[c]) > eps) {
      std::cerr << "For solution [" << c << "], the recorded score was " << scores[c] << " but extracted domains sum to " << score << "\n";
    }
    ++c;
  }

  return solutions;
}

vector<Domain> ArmatusDAG::viterbiPath() {
	vector<Domain> domains;
  const size_t INVALID = std::numeric_limits<size_t>::max();
	size_t end = params->n-1;
	//std::cerr << "Best score is " << subProbs[end].topK[0].score << "\n";

	while (subProbs[end].topK[0].edge != INVALID) {
		size_t begin = subProbs[end].topK[0].edge;
		domains.push_back({begin+1, end});
		end = begin;
	}

    sort(domains.begin(), domains.end());

	return domains;
}
<commit_msg>Indenting changes<commit_after>/*
    Authors: Darya Filippova, Geet Duggal, Rob Patro
    dfilippo | geet | robp @cs.cmu.edu
*/

#include <limits>
#include <boost/heap/binomial_heap.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include "ArmatusDAG.hpp"

ArmatusDAG::ArmatusDAG(ArmatusParams& p) :
	subProbs(SubProbsVec(p.n)),
    edgeWeights(EdgeWeightsVec(p.n, vector<double>())) {
	params = &p;
}

void ArmatusDAG::build() {
	// Since building the DAG visits everything in the same order as computing
	// a single optimial solution, I've had this function also fill out the
	// necessary information to obtain a backtrace of the opt. sln.
	subProbs[0].topK.push_back({std::numeric_limits<size_t>::max(), 0, 0.0});
	// What's the right condition here?
	// subProbs[1].topK.push_back({0, 0, std::max(q(0,1), 0.0)});

    for (size_t l : boost::irange(size_t{1}, params->n)) {
        // was this
  	    // edgeWeights[l].resize(l-1);
        // now this
  	    edgeWeights[l].resize(l);
  	    size_t chosenEdge = 0;
  	    double bestScore = 0.0;
  	    for (size_t k : boost::irange(size_t{0}, l)) {
  	    	// The last domain is [k,l]
  	    	double edgeWeight = std::max(q(k, l), 0.0);
            edgeWeights[l][k] = edgeWeight;
            double totalScore = edgeWeight;
            bool isDomain = edgeWeight > 0.0;
            bool isPrevDomain = (k == 0) ? true : false;
            if (k > 0) {
                double prevDomainScore = subProbs[k-1].topK[0].score;
                isPrevDomain = prevDomainScore > 0.0;
                // The score of this solution is the benefit we get from traversing
                // the edge + the best score available at the child
                totalScore += prevDomainScore;
             }
             if (isDomain or isPrevDomain) {
                 if (totalScore > bestScore) {
                     bestScore = totalScore;
                     chosenEdge = k;
                 }
            }
  	    }

  	    // Put our best solution on the stack.
  	    subProbs[l].topK.push_back({chosenEdge, 0, bestScore});
    }
}

double ArmatusDAG::s(size_t k, size_t l) {
	size_t d = l-k+1;
    return params->sums(k, l)/ std::pow(static_cast<double>(d),params->gamma);
}

double ArmatusDAG::q(size_t k, size_t l) {
	size_t d = l-k+1;
	return (s(k, l) - params->mu[d]);
}

/**
*  This interface is *wrong* but I wanted to sketch the
*  basic algo.
**/
void ArmatusDAG::computeTopK(uint32_t k) {
    for (size_t l : boost::irange(size_t{1}, params->n)) {
        std::function<bool (const BackPointer&, const BackPointer&)> BackPointerComparator = [l, this] (const BackPointer& x, const BackPointer& y) -> bool {
            auto scoreX = this->edgeWeights[l][x.edge];
            if (x.edge > 0) { scoreX += this->subProbs[x.edge-1].topK[x.childSolution].score; }
            auto scoreY = this->edgeWeights[l][y.edge];
            if (y.edge > 0) { scoreY += this->subProbs[y.edge-1].topK[y.childSolution].score; }

            return scoreX < scoreY;
        };

        boost::heap::binomial_heap<BackPointer,
            boost::heap::compare<decltype(BackPointerComparator)>> pq(BackPointerComparator);
        for (size_t j : boost::irange(size_t{0}, l)) {
            if (j > 0) {
                size_t i = j - 1;
                bool isDomain = edgeWeights[l][j] > 0.0;
                bool prevIsDomain = (subProbs[i].topK.size() > 0 and edgeWeights[i].size() > 0) ? edgeWeights[i][subProbs[i].topK[0].edge] > 0 : true;
                if (j == 1) { prevIsDomain = false; }

                if (isDomain or prevIsDomain) {
                    double score = edgeWeights[l][j] + subProbs[i].topK[0].score;
                    pq.push({j, 0, score});
                }
            } else {
                double score = edgeWeights[l][0];
                pq.push({0, 0, score});
            }
        }

        while (subProbs[l].topK.size() < k and !pq.empty()) {
            auto bp = pq.top();
            pq.pop();
            size_t j = bp.edge;
            if (j > 0) {
                bool alreadyFound{false};
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
                size_t nextSlnIdx = bp.childSolution + 1;
                bool isDomain = edgeWeights[l][j] > 0.0;

                size_t i = j - 1;
                //std::cout << bp.edge << "\t" << subProbs.size() << endl;
                if (nextSlnIdx < subProbs[i].topK.size()) {
                    bool prevIsDomain = edgeWeights[i][subProbs[i].topK[nextSlnIdx].edge] > 0.0;
                    if (isDomain or prevIsDomain ) {
                        double score = edgeWeights[l][j] + subProbs[i].topK[nextSlnIdx].score;
                        pq.push({j, nextSlnIdx, score});
                    }
                }
            } else {
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
            }
        }
    }

    // size_t sln = 0;
    // while (sln < k and sln < subProbs[params->n-1].topK.size()) {
    // 	std::cerr << "solution " << sln << " has score " << subProbs[params->n-1].topK[sln].score << "\n";
    // 	++sln;
    // }
}

WeightedDomainEnsemble ArmatusDAG::extractTopK(uint32_t k) {

  const size_t INVALID = std::numeric_limits<size_t>::max();
  // We skip 0 since that was already extracted by viterbiPath
  uint32_t currSln{0};

  WeightedDomainEnsemble solutions{ DomainEnsemble(k, DomainSet()), Weights(k, 0.0) };
  auto root = params->n-1;
  auto topScore = subProbs[root].topK[0].score;
  auto scores = Weights(k, 0.0);

  while (currSln < k and currSln < subProbs[root].topK.size()) {
    auto currentScore = subProbs[root].topK[currSln].score;
    scores[currSln] = currentScore;
    auto& currentDomainSet = solutions.domainSets[currSln];
    solutions.weights[currSln] = currentScore / topScore;

    // Which solution to use at the child
    auto bp = currSln;
    int64_t end = params->n-1;
    bool prevWasDomain = true;
    bool done{false};
    Domain prevDomain(root, root);

    while (end > 0) { // and subProbs[end].topK[bp].edge != INVALID) {
      //std::cerr << "end: " << end << "\n";
      size_t begin = subProbs[end].topK[bp].edge;
      size_t start = begin;
//      if (subProbs[begin].topK[subProbs[end].topK[bp].childSolution].edge != INVALID)
//         start++;
      Domain d(start, end);
      if (d.score(*params) > 0.0){
         currentDomainSet.push_back(d);
         prevWasDomain = true;
      } else {
         //currentDomainSet.push_back(d);
        if (!prevWasDomain) {
                std::cerr << "WHAT: solution contained two adjacent non-domains; current domain is (" << start << ", " << end << ") prev domain was (" << prevDomain.start << ", " << prevDomain.end << ")\n";
        }
        prevWasDomain = false;
      }
      prevDomain = d;
      bp = subProbs[end].topK[bp].childSolution;
      end = begin-1;
   }

    ++currSln;
  }

  /**
   * consistency check all the extracted domains (for debug purposes only,
   * take this out for release / speed).
   */
  size_t c = 0;
  double eps = 1e-3;
  for (auto& ds : solutions.domainSets) {
    double score = 0.0;
    for (auto& d : ds) {
      score += d.score(*params);
    }
    if (std::abs(score - scores[c]) > eps) {
      std::cerr << "For solution [" << c << "], the recorded score was " << scores[c] << " but extracted domains sum to " << score << "\n";
    }
    ++c;
  }

  return solutions;
}

vector<Domain> ArmatusDAG::viterbiPath() {
	vector<Domain> domains;
  const size_t INVALID = std::numeric_limits<size_t>::max();
	size_t end = params->n-1;
	//std::cerr << "Best score is " << subProbs[end].topK[0].score << "\n";

	while (subProbs[end].topK[0].edge != INVALID) {
		size_t begin = subProbs[end].topK[0].edge;
		domains.push_back({begin+1, end});
		end = begin;
	}

    sort(domains.begin(), domains.end());

	return domains;
}
<|endoftext|>


<commit_before>// Tests to drive abstract sharing analysis

#include "types.h"
#include "user.h"
#include "mtrace.h"

#include <string.h>

int
main(int ac, char **av)
{
  if (ac == 2 && strcmp(av[1], "on") == 0)
    mtenable_type(mtrace_record_ascope, "xv6-asharing");
  else if (ac == 2 && strcmp(av[1], "off") == 0)
    mtdisable("xv6-asharing");
  else
    die("usage: %s on|off\n", av[0]);
}
<commit_msg>bin/avar.cc: add an "onkern" option<commit_after>// Tests to drive abstract sharing analysis

#include "types.h"
#include "user.h"
#include "mtrace.h"

#include <string.h>

int
main(int ac, char **av)
{
  if (ac == 2 && strcmp(av[1], "on") == 0)
    mtenable_type(mtrace_record_ascope, "xv6-asharing");
  else if (ac == 2 && strcmp(av[1], "onkern") == 0)
    mtenable_type(mtrace_record_kernelscope, "xv6-asharing");
  else if (ac == 2 && strcmp(av[1], "off") == 0)
    mtdisable("xv6-asharing");
  else
    die("usage: %s on|onkern|off\n", av[0]);
}
<|endoftext|>


<commit_before>//===- MC-X86Specific.cpp - X86-Specific code for MC ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements X86-specific parsing, encoding and decoding stuff for
// MC.
//
//===----------------------------------------------------------------------===//

#include "AsmParser.h"
#include "llvm/MC/MCInst.h"
using namespace llvm;

/// X86Operand - Instances of this class represent one X86 machine instruction.
struct AsmParser::X86Operand {
  enum {
    Register,
    Immediate,
    Memory
  } Kind;

  union {
    struct {
      unsigned RegNo;
    } Reg;

    struct {
      MCValue Val;
    } Imm;

    struct {
      unsigned SegReg;
      MCValue Disp;
      unsigned BaseReg;
      unsigned IndexReg;
      unsigned Scale;
    } Mem;
  };

  unsigned getReg() const {
    assert(Kind == Register && "Invalid access!");
    return Reg.RegNo;
  }

  static X86Operand CreateReg(unsigned RegNo) {
    X86Operand Res;
    Res.Kind = Register;
    Res.Reg.RegNo = RegNo;
    return Res;
  }
  static X86Operand CreateImm(MCValue Val) {
    X86Operand Res;
    Res.Kind = Immediate;
    Res.Imm.Val = Val;
    return Res;
  }
  static X86Operand CreateMem(unsigned SegReg, MCValue Disp, unsigned BaseReg,
                              unsigned IndexReg, unsigned Scale) {
    // If there is no index register, we should never have a scale, and we
    // should always have a scale (in {1,2,4,8}) if we do.
    assert(((Scale == 0 && !IndexReg) ||
            (IndexReg && (Scale == 1 || Scale == 2 ||
                          Scale == 4 || Scale == 8))) &&
           "Invalid scale!");
    X86Operand Res;
    Res.Kind = Memory;
    Res.Mem.SegReg   = SegReg;
    Res.Mem.Disp     = Disp;
    Res.Mem.BaseReg  = BaseReg;
    Res.Mem.IndexReg = IndexReg;
    Res.Mem.Scale    = Scale;
    return Res;
  }
};

bool AsmParser::ParseX86Register(X86Operand &Op) {
  assert(Lexer.getKind() == asmtok::Register && "Invalid token kind!");

  // FIXME: Decode register number.
  Op = X86Operand::CreateReg(123);
  Lexer.Lex(); // Eat register token.

  return false;
}

bool AsmParser::ParseX86Operand(X86Operand &Op) {
  switch (Lexer.getKind()) {
  default:
    return ParseX86MemOperand(Op);
  case asmtok::Register:
    // FIXME: if a segment register, this could either be just the seg reg, or
    // the start of a memory operand.
    return ParseX86Register(Op);
  case asmtok::Dollar: {
    // $42 -> immediate.
    Lexer.Lex();
    MCValue Val;
    if (ParseRelocatableExpression(Val))
      return true;
    Op = X86Operand::CreateImm(Val);
    return false;
  }
  case asmtok::Star: {
    Lexer.Lex(); // Eat the star.

    if (Lexer.is(asmtok::Register)) {
      if (ParseX86Register(Op))
        return true;
    } else if (ParseX86MemOperand(Op))
      return true;

    // FIXME: Note the '*' in the operand for use by the matcher.
    return false;
  }
  }
}

/// ParseX86MemOperand: segment: disp(basereg, indexreg, scale)
bool AsmParser::ParseX86MemOperand(X86Operand &Op) {
  // FIXME: If SegReg ':'  (e.g. %gs:), eat and remember.
  unsigned SegReg = 0;

  // We have to disambiguate a parenthesized expression "(4+5)" from the start
  // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)".  The
  // only way to do this without lookahead is to eat the ( and see what is after
  // it.
  MCValue Disp = MCValue::get(0, 0, 0);
  if (Lexer.isNot(asmtok::LParen)) {
    if (ParseRelocatableExpression(Disp)) return true;

    // After parsing the base expression we could either have a parenthesized
    // memory address or not.  If not, return now.  If so, eat the (.
    if (Lexer.isNot(asmtok::LParen)) {
      Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0);
      return false;
    }

    // Eat the '('.
    Lexer.Lex();
  } else {
    // Okay, we have a '('.  We don't know if this is an expression or not, but
    // so we have to eat the ( to see beyond it.
    Lexer.Lex(); // Eat the '('.

    if (Lexer.is(asmtok::Register) || Lexer.is(asmtok::Comma)) {
      // Nothing to do here, fall into the code below with the '(' part of the
      // memory operand consumed.
    } else {
      // It must be an parenthesized expression, parse it now.
      if (ParseParenRelocatableExpression(Disp))
        return true;

      // After parsing the base expression we could either have a parenthesized
      // memory address or not.  If not, return now.  If so, eat the (.
      if (Lexer.isNot(asmtok::LParen)) {
        Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0);
        return false;
      }

      // Eat the '('.
      Lexer.Lex();
    }
  }

  // If we reached here, then we just ate the ( of the memory operand.  Process
  // the rest of the memory operand.
  unsigned BaseReg = 0, IndexReg = 0, Scale = 0;

  if (Lexer.is(asmtok::Register)) {
    if (ParseX86Register(Op))
      return true;
    BaseReg = Op.getReg();
  }

  if (Lexer.is(asmtok::Comma)) {
    Lexer.Lex(); // eat the comma.

    if (Lexer.is(asmtok::Register)) {
      if (ParseX86Register(Op))
        return true;
      IndexReg = Op.getReg();
      Scale = 1;      // If not specified, the scale defaults to 1.
    }

    if (Lexer.is(asmtok::Comma)) {
      Lexer.Lex(); // Eat the comma.

      // If present, get and validate scale amount.
      if (Lexer.is(asmtok::IntVal)) {
        int64_t ScaleVal = Lexer.getCurIntVal();
        if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8)
          return TokError("scale factor in address must be 1, 2, 4 or 8");
        Lexer.Lex();  // eat the scale.
        Scale = (unsigned)ScaleVal;
      }
    }
  }

  // Ok, we've eaten the memory operand, verify we have a ')' and eat it too.
  if (Lexer.isNot(asmtok::RParen))
    return TokError("unexpected token in memory operand");
  Lexer.Lex(); // Eat the ')'.

  Op = X86Operand::CreateMem(SegReg, Disp, BaseReg, IndexReg, Scale);
  return false;
}

/// MatchX86Inst - Convert a parsed instruction name and operand list into a
/// concrete instruction.
static bool MatchX86Inst(const char *Name,
                         llvm::SmallVector<AsmParser::X86Operand, 3> &Operands,
                         MCInst &Inst) {
  return false;
}

/// ParseX86InstOperands - Parse the operands of an X86 instruction and return
/// them as the operands of an MCInst.
bool AsmParser::ParseX86InstOperands(const char *InstName, MCInst &Inst) {
  llvm::SmallVector<X86Operand, 3> Operands;

  if (Lexer.isNot(asmtok::EndOfStatement)) {
    // Read the first operand.
    Operands.push_back(X86Operand());
    if (ParseX86Operand(Operands.back()))
      return true;

    while (Lexer.is(asmtok::Comma)) {
      Lexer.Lex();  // Eat the comma.

      // Parse and remember the operand.
      Operands.push_back(X86Operand());
      if (ParseX86Operand(Operands.back()))
        return true;
    }
  }

  return MatchX86Inst(InstName, Operands, Inst);
}
<commit_msg>llvm-mc/x86: Fix various nit-picky bugs in displacement parsing.  - Test case to follow.<commit_after>//===- MC-X86Specific.cpp - X86-Specific code for MC ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements X86-specific parsing, encoding and decoding stuff for
// MC.
//
//===----------------------------------------------------------------------===//

#include "AsmParser.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Support/SourceMgr.h"
using namespace llvm;

/// X86Operand - Instances of this class represent one X86 machine instruction.
struct AsmParser::X86Operand {
  enum {
    Register,
    Immediate,
    Memory
  } Kind;

  union {
    struct {
      unsigned RegNo;
    } Reg;

    struct {
      MCValue Val;
    } Imm;

    struct {
      unsigned SegReg;
      MCValue Disp;
      unsigned BaseReg;
      unsigned IndexReg;
      unsigned Scale;
    } Mem;
  };

  unsigned getReg() const {
    assert(Kind == Register && "Invalid access!");
    return Reg.RegNo;
  }

  static X86Operand CreateReg(unsigned RegNo) {
    X86Operand Res;
    Res.Kind = Register;
    Res.Reg.RegNo = RegNo;
    return Res;
  }
  static X86Operand CreateImm(MCValue Val) {
    X86Operand Res;
    Res.Kind = Immediate;
    Res.Imm.Val = Val;
    return Res;
  }
  static X86Operand CreateMem(unsigned SegReg, MCValue Disp, unsigned BaseReg,
                              unsigned IndexReg, unsigned Scale) {
    // If there is no index register, we should never have a scale, and we
    // should always have a scale (in {1,2,4,8}) if we do.
    assert(((Scale == 0 && !IndexReg) ||
            (IndexReg && (Scale == 1 || Scale == 2 ||
                          Scale == 4 || Scale == 8))) &&
           "Invalid scale!");
    X86Operand Res;
    Res.Kind = Memory;
    Res.Mem.SegReg   = SegReg;
    Res.Mem.Disp     = Disp;
    Res.Mem.BaseReg  = BaseReg;
    Res.Mem.IndexReg = IndexReg;
    Res.Mem.Scale    = Scale;
    return Res;
  }
};

bool AsmParser::ParseX86Register(X86Operand &Op) {
  assert(Lexer.getKind() == asmtok::Register && "Invalid token kind!");

  // FIXME: Decode register number.
  Op = X86Operand::CreateReg(123);
  Lexer.Lex(); // Eat register token.

  return false;
}

bool AsmParser::ParseX86Operand(X86Operand &Op) {
  switch (Lexer.getKind()) {
  default:
    return ParseX86MemOperand(Op);
  case asmtok::Register:
    // FIXME: if a segment register, this could either be just the seg reg, or
    // the start of a memory operand.
    return ParseX86Register(Op);
  case asmtok::Dollar: {
    // $42 -> immediate.
    Lexer.Lex();
    MCValue Val;
    if (ParseRelocatableExpression(Val))
      return true;
    Op = X86Operand::CreateImm(Val);
    return false;
  }
  case asmtok::Star: {
    Lexer.Lex(); // Eat the star.

    if (Lexer.is(asmtok::Register)) {
      if (ParseX86Register(Op))
        return true;
    } else if (ParseX86MemOperand(Op))
      return true;

    // FIXME: Note the '*' in the operand for use by the matcher.
    return false;
  }
  }
}

/// ParseX86MemOperand: segment: disp(basereg, indexreg, scale)
bool AsmParser::ParseX86MemOperand(X86Operand &Op) {
  // FIXME: If SegReg ':'  (e.g. %gs:), eat and remember.
  unsigned SegReg = 0;

  // We have to disambiguate a parenthesized expression "(4+5)" from the start
  // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)".  The
  // only way to do this without lookahead is to eat the ( and see what is after
  // it.
  MCValue Disp = MCValue::get(0, 0, 0);
  if (Lexer.isNot(asmtok::LParen)) {
    if (ParseRelocatableExpression(Disp)) return true;

    // After parsing the base expression we could either have a parenthesized
    // memory address or not.  If not, return now.  If so, eat the (.
    if (Lexer.isNot(asmtok::LParen)) {
      Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0);
      return false;
    }

    // Eat the '('.
    Lexer.Lex();
  } else {
    // Okay, we have a '('.  We don't know if this is an expression or not, but
    // so we have to eat the ( to see beyond it.
    Lexer.Lex(); // Eat the '('.

    if (Lexer.is(asmtok::Register) || Lexer.is(asmtok::Comma)) {
      // Nothing to do here, fall into the code below with the '(' part of the
      // memory operand consumed.
    } else {
      // It must be an parenthesized expression, parse it now.
      if (ParseParenRelocatableExpression(Disp))
        return true;

      // After parsing the base expression we could either have a parenthesized
      // memory address or not.  If not, return now.  If so, eat the (.
      if (Lexer.isNot(asmtok::LParen)) {
        Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0);
        return false;
      }

      // Eat the '('.
      Lexer.Lex();
    }
  }

  // If we reached here, then we just ate the ( of the memory operand.  Process
  // the rest of the memory operand.
  unsigned BaseReg = 0, IndexReg = 0, Scale = 0;

  if (Lexer.is(asmtok::Register)) {
    if (ParseX86Register(Op))
      return true;
    BaseReg = Op.getReg();
  }

  if (Lexer.is(asmtok::Comma)) {
    Lexer.Lex(); // Eat the comma.

    // Following the comma we should have either an index register, or a scale
    // value. We don't support the later form, but we want to parse it
    // correctly.
    //
    // Not that even though it would be completely consistent to support syntax
    // like "1(%eax,,1)", the assembler doesn't.
    if (Lexer.is(asmtok::Register)) {
      if (ParseX86Register(Op))
        return true;
      IndexReg = Op.getReg();
      Scale = 1;      // If not specified, the scale defaults to 1.

      if (Lexer.isNot(asmtok::RParen)) {
        // Parse the scale amount:
        //  ::= ',' [scale-expression]
        if (Lexer.isNot(asmtok::Comma))
          return true;
        Lexer.Lex(); // Eat the comma.

        if (Lexer.isNot(asmtok::RParen)) {
          int64_t ScaleVal;
          if (ParseAbsoluteExpression(ScaleVal))
            return true;

          // Validate the scale amount.
          if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8)
            return TokError("scale factor in address must be 1, 2, 4 or 8");
          Scale = (unsigned)ScaleVal;
        }
      }
    } else if (Lexer.isNot(asmtok::RParen)) {
      // Otherwise we have the unsupported form of a scale amount without an
      // index.
      SMLoc Loc = Lexer.getLoc();

      int64_t Value;
      if (ParseAbsoluteExpression(Value))
        return true;

      return Error(Loc, "cannot have scale factor without index register");
    }
  }

  // Ok, we've eaten the memory operand, verify we have a ')' and eat it too.
  if (Lexer.isNot(asmtok::RParen))
    return TokError("unexpected token in memory operand");
  Lexer.Lex(); // Eat the ')'.

  Op = X86Operand::CreateMem(SegReg, Disp, BaseReg, IndexReg, Scale);
  return false;
}

/// MatchX86Inst - Convert a parsed instruction name and operand list into a
/// concrete instruction.
static bool MatchX86Inst(const char *Name,
                         llvm::SmallVector<AsmParser::X86Operand, 3> &Operands,
                         MCInst &Inst) {
  return false;
}

/// ParseX86InstOperands - Parse the operands of an X86 instruction and return
/// them as the operands of an MCInst.
bool AsmParser::ParseX86InstOperands(const char *InstName, MCInst &Inst) {
  llvm::SmallVector<X86Operand, 3> Operands;

  if (Lexer.isNot(asmtok::EndOfStatement)) {
    // Read the first operand.
    Operands.push_back(X86Operand());
    if (ParseX86Operand(Operands.back()))
      return true;

    while (Lexer.is(asmtok::Comma)) {
      Lexer.Lex();  // Eat the comma.

      // Parse and remember the operand.
      Operands.push_back(X86Operand());
      if (ParseX86Operand(Operands.back()))
        return true;
    }
  }

  return MatchX86Inst(InstName, Operands, Inst);
}
<|endoftext|>