<commit_before>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
/*
 * Copyright (C) 2014 the FFLAS-FFPACK group
 *
 * Written by   Bastien Vialla <bastien.vialla@lirmm.fr>
 *
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK 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 Street, Fifth Floor, Boston, MA  02110-1301 USA
 * ========LICENCE========
 *.
 */

#ifndef __FFLASFFPACK_fflas_sparse_HYB_ZO_utils_INL
#define __FFLASFFPACK_fflas_sparse_HYB_ZO_utils_INL

namespace FFLAS {

// #define HYB_ZO_DEBUG 1

template <class Field> inline void sparse_delete(const Sparse<Field, SparseMatrix_t::HYB_ZO> &A) {
    if (A.dat != nullptr)
        sparse_delete(*(A.dat));
    if (A.one != nullptr)
        sparse_delete(*(A.one));
    if (A.mone != nullptr)
        sparse_delete(*(A.mone));
}

template <class Field, class IndexT>
inline void sparse_init(const Field &F, Sparse<Field, SparseMatrix_t::HYB_ZO> &A, const IndexT *row, const IndexT *col,
                        typename Field::ConstElement_ptr dat, uint64_t rowdim, uint64_t coldim, uint64_t nnz) {

    A.m = rowdim;
    A.n = coldim;
    A.nnz = nnz;
    A.delayed = true;
    A.nElements = nnz;
    uint64_t nOnes = 0, nMOnes = 0, nOthers = 0;
    for (uint64_t i = 0; i < nnz; ++i) {
        if (F.isOne(dat[i]))
            nOnes++;
        else if (F.isMOne(dat[i]))
            nMOnes++;
        else
            nOthers++;
    }

    typename Field::Element_ptr dat2;
    index_t *colOne = nullptr, *colMOne = nullptr, *colOther = nullptr, *rowOne = nullptr, *rowMOne = nullptr,
            *rowOther = nullptr;
    if (nOnes) {
        colOne = fflas_new<index_t>(nOnes, Alignment::CACHE_LINE);
        rowOne = fflas_new<index_t>(nOnes, Alignment::CACHE_LINE);
    }
    if (nMOnes) {
        colMOne = fflas_new<index_t>(nMOnes, Alignment::CACHE_LINE);
        rowMOne = fflas_new<index_t>(nMOnes, Alignment::CACHE_LINE);
    }
    if (nOthers) {
        dat2 = fflas_new(F, nOthers, 1, Alignment::CACHE_LINE);
        colOther = fflas_new<index_t>(nOthers, Alignment::CACHE_LINE);
        rowOther = fflas_new<index_t>(nOthers, Alignment::CACHE_LINE);
    }

    uint64_t itOne = 0, itMOne = 0, itOther = 0;
    for (uint64_t i = 0; i < nnz; ++i) {
        if (F.isOne(dat[i])) {
            colOne[itOne] = col[i];
            rowOne[itOne] = row[i];
            ++itOne;
        } else if (F.isMOne(dat[i])) {
            colMOne[itMOne] = col[i];
            rowMOne[itMOne] = row[i];
            ++itMOne;
        } else {
            dat2[itOther] = dat[i];
            colOther[itOther] = col[i];
            rowOther[itOther] = row[i];
            ++itOther;
        }
    }

    if (nOnes) {
        A.one = new Sparse<Field, SparseMatrix_t::CSR_ZO>();
        sparse_init(F, *(A.one), rowOne, colOne, nullptr, rowdim, coldim, nOnes);
    }
    if (nMOnes) {
        A.mone = new Sparse<Field, SparseMatrix_t::CSR_ZO>();
        sparse_init(F, *(A.mone), rowMOne, colMOne, nullptr, rowdim, coldim, nMOnes);
        A.mone->cst = -1;
    }
    if (nOthers) {
        A.dat = new Sparse<Field, SparseMatrix_t::CSR>();
        sparse_init(F, *(A.dat), rowOther, colOther, dat2, rowdim, coldim, nOthers);
    }

    if (nOnes) {
        fflas_delete(colOne);
        fflas_delete(rowOne);
    }
    if (nMOnes) {
        fflas_delete(colMOne);
        fflas_delete(rowMOne);
    }
    if (nOthers) {
        fflas_delete(colOther);
        fflas_delete(rowOther);
        fflas_delete(dat2);
    }
}

template<typename _Field>
std::ostream& operator<<(std::ostream& os, const Sparse<_Field, SparseMatrix_t::HYB_ZO>& A) {
	sparse_print(os << "non-ones: ", *(A.dat));
}

}

#endif
<commit_msg>return os<commit_after>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
/*
 * Copyright (C) 2014 the FFLAS-FFPACK group
 *
 * Written by   Bastien Vialla <bastien.vialla@lirmm.fr>
 *
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK 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 Street, Fifth Floor, Boston, MA  02110-1301 USA
 * ========LICENCE========
 *.
 */

#ifndef __FFLASFFPACK_fflas_sparse_HYB_ZO_utils_INL
#define __FFLASFFPACK_fflas_sparse_HYB_ZO_utils_INL

namespace FFLAS {

// #define HYB_ZO_DEBUG 1

template <class Field> inline void sparse_delete(const Sparse<Field, SparseMatrix_t::HYB_ZO> &A) {
    if (A.dat != nullptr)
        sparse_delete(*(A.dat));
    if (A.one != nullptr)
        sparse_delete(*(A.one));
    if (A.mone != nullptr)
        sparse_delete(*(A.mone));
}

template <class Field, class IndexT>
inline void sparse_init(const Field &F, Sparse<Field, SparseMatrix_t::HYB_ZO> &A, const IndexT *row, const IndexT *col,
                        typename Field::ConstElement_ptr dat, uint64_t rowdim, uint64_t coldim, uint64_t nnz) {

    A.m = rowdim;
    A.n = coldim;
    A.nnz = nnz;
    A.delayed = true;
    A.nElements = nnz;
    uint64_t nOnes = 0, nMOnes = 0, nOthers = 0;
    for (uint64_t i = 0; i < nnz; ++i) {
        if (F.isOne(dat[i]))
            nOnes++;
        else if (F.isMOne(dat[i]))
            nMOnes++;
        else
            nOthers++;
    }

    typename Field::Element_ptr dat2;
    index_t *colOne = nullptr, *colMOne = nullptr, *colOther = nullptr, *rowOne = nullptr, *rowMOne = nullptr,
            *rowOther = nullptr;
    if (nOnes) {
        colOne = fflas_new<index_t>(nOnes, Alignment::CACHE_LINE);
        rowOne = fflas_new<index_t>(nOnes, Alignment::CACHE_LINE);
    }
    if (nMOnes) {
        colMOne = fflas_new<index_t>(nMOnes, Alignment::CACHE_LINE);
        rowMOne = fflas_new<index_t>(nMOnes, Alignment::CACHE_LINE);
    }
    if (nOthers) {
        dat2 = fflas_new(F, nOthers, 1, Alignment::CACHE_LINE);
        colOther = fflas_new<index_t>(nOthers, Alignment::CACHE_LINE);
        rowOther = fflas_new<index_t>(nOthers, Alignment::CACHE_LINE);
    }

    uint64_t itOne = 0, itMOne = 0, itOther = 0;
    for (uint64_t i = 0; i < nnz; ++i) {
        if (F.isOne(dat[i])) {
            colOne[itOne] = col[i];
            rowOne[itOne] = row[i];
            ++itOne;
        } else if (F.isMOne(dat[i])) {
            colMOne[itMOne] = col[i];
            rowMOne[itMOne] = row[i];
            ++itMOne;
        } else {
            dat2[itOther] = dat[i];
            colOther[itOther] = col[i];
            rowOther[itOther] = row[i];
            ++itOther;
        }
    }

    if (nOnes) {
        A.one = new Sparse<Field, SparseMatrix_t::CSR_ZO>();
        sparse_init(F, *(A.one), rowOne, colOne, nullptr, rowdim, coldim, nOnes);
    }
    if (nMOnes) {
        A.mone = new Sparse<Field, SparseMatrix_t::CSR_ZO>();
        sparse_init(F, *(A.mone), rowMOne, colMOne, nullptr, rowdim, coldim, nMOnes);
        A.mone->cst = -1;
    }
    if (nOthers) {
        A.dat = new Sparse<Field, SparseMatrix_t::CSR>();
        sparse_init(F, *(A.dat), rowOther, colOther, dat2, rowdim, coldim, nOthers);
    }

    if (nOnes) {
        fflas_delete(colOne);
        fflas_delete(rowOne);
    }
    if (nMOnes) {
        fflas_delete(colMOne);
        fflas_delete(rowMOne);
    }
    if (nOthers) {
        fflas_delete(colOther);
        fflas_delete(rowOther);
        fflas_delete(dat2);
    }
}

template<typename _Field>
std::ostream& operator<<(std::ostream& os, const Sparse<_Field, SparseMatrix_t::HYB_ZO>& A) {
	return sparse_print(os << "non-ones: ", *(A.dat));
}

}

#endif
<|endoftext|>


<commit_before><commit_msg>Marking BrowserEncodingTest.TestEncodingAutoDetect as FLAKY. <commit_after><|endoftext|>


<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 == "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_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_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/pdc: Parse simple clock constraints<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,
    } 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
<|endoftext|>


<commit_before>#include "unicode-utils.h"

#include <stdlib.h>
#include <string.h>
#include <locale.h>

int UnicodeUtils::characters_in_bytes(const char* string, int bytes) {
  if (bytes == 0)
    return 0;

  mblen(NULL, 0);
  setlocale(LC_CTYPE, "en_US.UTF-8");

  int characters = 0;
  while (bytes > 0) {
    int characterLength = mblen(string, bytes);
    if (characterLength < 1)
      break;
    if (characterLength == 4)
      characters += 2; /* High/low surrogate pair of two characters */
    else
      characters++;
    bytes -= characterLength;
    string += characterLength;
  }
  return characters;
}

int UnicodeUtils::bytes_in_characters(const wchar_t* string, int bytes) {
  if (characters == 0)
    return 0;

  mblen(NULL, 0);
  setlocale(LC_CTYPE, "en_US.UTF-8");

  int bytes = 0;
  int length = strlen(string);
  while (length > 0) {
    int characterLength = mblen(string, length);
    if (characterLength < 1)
      break;

    bytes += characterLength;
    if (--characters == 0)
      break;

    length -= characterLength;
    string += characterLength;
  }
  return bytes;
}
<commit_msg>:lipstick: fix typo.<commit_after>#include "unicode-utils.h"

#include <stdlib.h>
#include <string.h>
#include <locale.h>

int UnicodeUtils::characters_in_bytes(const char* string, int bytes) {
  if (bytes == 0)
    return 0;

  mblen(NULL, 0);
  setlocale(LC_CTYPE, "en_US.UTF-8");

  int characters = 0;
  while (bytes > 0) {
    int characterLength = mblen(string, bytes);
    if (characterLength < 1)
      break;
    if (characterLength == 4)
      characters += 2; /* High/low surrogate pair of two characters */
    else
      characters++;
    bytes -= characterLength;
    string += characterLength;
  }
  return characters;
}

int UnicodeUtils::bytes_in_characters(const char* string, int characters) {
  if (characters == 0)
    return 0;

  mblen(NULL, 0);
  setlocale(LC_CTYPE, "en_US.UTF-8");

  int bytes = 0;
  int length = strlen(string);
  while (length > 0) {
    int characterLength = mblen(string, length);
    if (characterLength < 1)
      break;

    bytes += characterLength;
    if (--characters == 0)
      break;

    length -= characterLength;
    string += characterLength;
  }
  return bytes;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_shelf.h"

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

// DownloadShelfContextMenu ----------------------------------------------------

DownloadShelfContextMenu::DownloadShelfContextMenu(
    BaseDownloadItemModel* download_model)
    : download_(download_model->download()),
      model_(download_model) {
}

DownloadShelfContextMenu::~DownloadShelfContextMenu() {
}

bool DownloadShelfContextMenu::ItemIsChecked(int id) const {
  switch (id) {
    case OPEN_WHEN_COMPLETE:
      return download_->open_when_complete();
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      return download_->manager()->ShouldOpenFileExtension(extension);
    }
  }
  return false;
}

bool DownloadShelfContextMenu::ItemIsDefault(int id) const {
  return id == OPEN_WHEN_COMPLETE;
}

std::wstring DownloadShelfContextMenu::GetItemLabel(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
      return l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW);
    case OPEN_WHEN_COMPLETE:
      if (download_->state() == DownloadItem::IN_PROGRESS)
        return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN);
    case ALWAYS_OPEN_TYPE:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    case CANCEL:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_CANCEL);
    case REMOVE_ITEM:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_REMOVE_ITEM);
    default:
      NOTREACHED();
  }
  return std::wstring();
}

bool DownloadShelfContextMenu::IsItemCommandEnabled(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
    case OPEN_WHEN_COMPLETE:
      return download_->state() != DownloadItem::CANCELLED;
    case ALWAYS_OPEN_TYPE:
      return download_util::CanOpenDownload(download_);
    case CANCEL:
      return download_->state() == DownloadItem::IN_PROGRESS;
    case REMOVE_ITEM:
      return download_->state() == DownloadItem::COMPLETE;
    default:
      return id > 0 && id < MENU_LAST;
  }
}

void DownloadShelfContextMenu::ExecuteItemCommand(int id) {
  switch (id) {
    case SHOW_IN_FOLDER:
      download_->manager()->ShowDownloadInShell(download_);
      break;
    case OPEN_WHEN_COMPLETE:
      download_util::OpenDownload(download_);
      break;
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      download_->manager()->OpenFilesOfExtension(
          extension, !ItemIsChecked(ALWAYS_OPEN_TYPE));
      break;
    }
    case CANCEL:
      model_->CancelTask();
      break;
    case REMOVE_ITEM:
      download_->Remove(false);
      break;
    default:
      NOTREACHED();
  }
}
<commit_msg>Allow cancellable download items to be removable from download shelf.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_shelf.h"

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

// DownloadShelfContextMenu ----------------------------------------------------

DownloadShelfContextMenu::DownloadShelfContextMenu(
    BaseDownloadItemModel* download_model)
    : download_(download_model->download()),
      model_(download_model) {
}

DownloadShelfContextMenu::~DownloadShelfContextMenu() {
}

bool DownloadShelfContextMenu::ItemIsChecked(int id) const {
  switch (id) {
    case OPEN_WHEN_COMPLETE:
      return download_->open_when_complete();
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      return download_->manager()->ShouldOpenFileExtension(extension);
    }
  }
  return false;
}

bool DownloadShelfContextMenu::ItemIsDefault(int id) const {
  return id == OPEN_WHEN_COMPLETE;
}

std::wstring DownloadShelfContextMenu::GetItemLabel(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
      return l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW);
    case OPEN_WHEN_COMPLETE:
      if (download_->state() == DownloadItem::IN_PROGRESS)
        return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN);
    case ALWAYS_OPEN_TYPE:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    case CANCEL:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_CANCEL);
    case REMOVE_ITEM:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_REMOVE_ITEM);
    default:
      NOTREACHED();
  }
  return std::wstring();
}

bool DownloadShelfContextMenu::IsItemCommandEnabled(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
    case OPEN_WHEN_COMPLETE:
      return download_->state() != DownloadItem::CANCELLED;
    case ALWAYS_OPEN_TYPE:
      return download_util::CanOpenDownload(download_);
    case CANCEL:
      return download_->state() == DownloadItem::IN_PROGRESS;
    case REMOVE_ITEM:
      return download_->state() == DownloadItem::COMPLETE ||
          download_->state() == DownloadItem::CANCELLED;
    default:
      return id > 0 && id < MENU_LAST;
  }
}

void DownloadShelfContextMenu::ExecuteItemCommand(int id) {
  switch (id) {
    case SHOW_IN_FOLDER:
      download_->manager()->ShowDownloadInShell(download_);
      break;
    case OPEN_WHEN_COMPLETE:
      download_util::OpenDownload(download_);
      break;
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      download_->manager()->OpenFilesOfExtension(
          extension, !ItemIsChecked(ALWAYS_OPEN_TYPE));
      break;
    }
    case CANCEL:
      model_->CancelTask();
      break;
    case REMOVE_ITEM:
      download_->Remove(false);
      break;
    default:
      NOTREACHED();
  }
}
<|endoftext|>


<commit_before>//===--- DependencyGraph.cpp - Track intra-module dependencies ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Driver/DependencyGraph.h"
#include "swift/Basic/Demangle.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"

using namespace swift;

enum class DependencyGraphImpl::DependencyKind : uint8_t {
  TopLevelName = 1 << 0,
  DynamicLookupName = 1 << 1,
  NominalType = 1 << 2,
  NominalTypeMember = 1 << 3,
  ExternalFile = 1 << 4,
};
enum class DependencyGraphImpl::DependencyFlags : uint8_t {
  IsCascading = 1 << 0
};

class DependencyGraphImpl::MarkTracerImpl::Entry {
public:
  const void *Node;
  StringRef Name;
  DependencyMaskTy KindMask;
};

DependencyGraphImpl::MarkTracerImpl::MarkTracerImpl() = default;
DependencyGraphImpl::MarkTracerImpl::~MarkTracerImpl() = default;

using LoadResult = DependencyGraphImpl::LoadResult;
using DependencyKind = DependencyGraphImpl::DependencyKind;
using DependencyCallbackTy = LoadResult(StringRef, DependencyKind, bool);
using InterfaceHashCallbackTy = LoadResult(StringRef);

static LoadResult
parseDependencyFile(llvm::MemoryBuffer &buffer,
                    llvm::function_ref<DependencyCallbackTy> providesCallback,
                    llvm::function_ref<DependencyCallbackTy> dependsCallback,
                    llvm::function_ref<InterfaceHashCallbackTy> interfaceHashCallback) {
  namespace yaml = llvm::yaml;

  // FIXME: Switch to a format other than YAML.
  llvm::SourceMgr SM;
  yaml::Stream stream(buffer.getMemBufferRef(), SM);
  auto I = stream.begin();
  if (I == stream.end() || !I->getRoot())
    return LoadResult::HadError;

  auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot());
  if (!topLevelMap) {
    if (isa<yaml::NullNode>(I->getRoot()))
      return LoadResult::UpToDate;
    return LoadResult::HadError;
  }

  LoadResult result = LoadResult::UpToDate;
  SmallString<64> scratch;

  // After an entry, we know more about the node as a whole.
  // Update the "result" variable above.
  // This is a macro rather than a lambda because it contains a return.
#define UPDATE_RESULT(update) switch (update) {\
    case LoadResult::HadError: \
      return LoadResult::HadError; \
    case LoadResult::UpToDate: \
      break; \
    case LoadResult::AffectsDownstream: \
      result = LoadResult::AffectsDownstream; \
      break; \
    } \

  // FIXME: LLVM's YAML support does incremental parsing in such a way that
  // for-range loops break.
  for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) {
    if (isa<yaml::NullNode>(i->getValue()))
      continue;

    auto *key = dyn_cast<yaml::ScalarNode>(i->getKey());
    if (!key)
      return LoadResult::HadError;
    StringRef keyString = key->getValue(scratch);

    if (keyString == "interface-hash") {
      auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
      if (!value)
        return LoadResult::HadError;

      StringRef valueString = value->getValue(scratch);
      UPDATE_RESULT(interfaceHashCallback(valueString));

    } else {
      enum class DependencyDirection : bool {
        Depends,
        Provides
      };
      using KindPair = std::pair<DependencyKind, DependencyDirection>;

      KindPair dirAndKind = llvm::StringSwitch<KindPair>(key->getValue(scratch))
        .Case("depends-top-level",
              std::make_pair(DependencyKind::TopLevelName,
                             DependencyDirection::Depends))
        .Case("depends-nominal",
              std::make_pair(DependencyKind::NominalType,
                             DependencyDirection::Depends))
        .Case("depends-member",
              std::make_pair(DependencyKind::NominalTypeMember,
                             DependencyDirection::Depends))
        .Case("depends-dynamic-lookup",
              std::make_pair(DependencyKind::DynamicLookupName,
                             DependencyDirection::Depends))
        .Case("depends-external",
              std::make_pair(DependencyKind::ExternalFile,
                             DependencyDirection::Depends))
        .Case("provides-top-level",
              std::make_pair(DependencyKind::TopLevelName,
                             DependencyDirection::Provides))
        .Case("provides-nominal",
              std::make_pair(DependencyKind::NominalType,
                             DependencyDirection::Provides))
        .Case("provides-member",
              std::make_pair(DependencyKind::NominalTypeMember,
                             DependencyDirection::Provides))
        .Case("provides-dynamic-lookup",
              std::make_pair(DependencyKind::DynamicLookupName,
                             DependencyDirection::Provides))
        .Default(std::make_pair(DependencyKind(),
                                DependencyDirection::Depends));
      if (dirAndKind.first == DependencyKind())
        return LoadResult::HadError;

      auto *entries = dyn_cast<yaml::SequenceNode>(i->getValue());
      if (!entries)
        return LoadResult::HadError;

      if (dirAndKind.first == DependencyKind::NominalTypeMember) {
        // Handle member dependencies specially. Rather than being a single
        // string, they come in the form ["{MangledBaseName}", "memberName"].
        for (yaml::Node &rawEntry : *entries) {
          bool isCascading = rawEntry.getRawTag() != "!private";

          auto *entry = dyn_cast<yaml::SequenceNode>(&rawEntry);
          if (!entry)
            return LoadResult::HadError;

          auto iter = entry->begin();
          auto *base = dyn_cast<yaml::ScalarNode>(&*iter);
          if (!base)
            return LoadResult::HadError;
          ++iter;

          auto *member = dyn_cast<yaml::ScalarNode>(&*iter);
          if (!member)
            return LoadResult::HadError;
          ++iter;

          // FIXME: LLVM's YAML support doesn't implement == correctly for end
          // iterators.
          assert(!(iter != entry->end()));

          bool isDepends = dirAndKind.second == DependencyDirection::Depends;
          auto &callback = isDepends ? dependsCallback : providesCallback;

          // Smash the type and member names together so we can continue using
          // StringMap.
          SmallString<64> appended;
          appended += base->getValue(scratch);
          appended.push_back('\0');
          appended += member->getValue(scratch);

          UPDATE_RESULT(callback(appended.str(), dirAndKind.first,
                                 isCascading));
        }
      } else {
        for (const yaml::Node &rawEntry : *entries) {
          auto *entry = dyn_cast<yaml::ScalarNode>(&rawEntry);
          if (!entry)
            return LoadResult::HadError;

          bool isDepends = dirAndKind.second == DependencyDirection::Depends;
          auto &callback = isDepends ? dependsCallback : providesCallback;

          UPDATE_RESULT(callback(entry->getValue(scratch), dirAndKind.first,
                                 entry->getRawTag() != "!private"));
        }
      }
    }
  }

  return result;
}

LoadResult DependencyGraphImpl::loadFromPath(const void *node, StringRef path) {
  auto buffer = llvm::MemoryBuffer::getFile(path);
  if (!buffer)
    return LoadResult::HadError;
  return loadFromBuffer(node, *buffer.get());
}

LoadResult
DependencyGraphImpl::loadFromString(const void *node, StringRef data) {
  auto buffer = llvm::MemoryBuffer::getMemBuffer(data);
  return loadFromBuffer(node, *buffer);
}

LoadResult DependencyGraphImpl::loadFromBuffer(const void *node,
                                               llvm::MemoryBuffer &buffer) {
  auto &provides = Provides[node];

  auto dependsCallback = [this, node](StringRef name, DependencyKind kind,
                                      bool isCascading) -> LoadResult {
    if (kind == DependencyKind::ExternalFile)
      ExternalDependencies.insert(name);

    auto &entries = Dependencies[name];
    auto iter = std::find_if(entries.first.begin(), entries.first.end(),
                             [node](const DependencyEntryTy &entry) -> bool {
      return node == entry.node;
    });

    DependencyFlagsTy flags;
    if (isCascading)
      flags |= DependencyFlags::IsCascading;

    if (iter == entries.first.end()) {
      entries.first.push_back({node, kind, flags});
    } else {
      iter->kindMask |= kind;
      iter->flags |= flags;
    }

    if (isCascading && (entries.second & kind))
      return LoadResult::AffectsDownstream;
    return LoadResult::UpToDate;
  };

  auto providesCallback =
      [this, node, &provides](StringRef name, DependencyKind kind,
                              bool isCascading) -> LoadResult {
    assert(isCascading);
    auto iter = std::find_if(provides.begin(), provides.end(),
                             [name](const ProvidesEntryTy &entry) -> bool {
      return name == entry.name;
    });

    if (iter == provides.end())
      provides.push_back({name, kind});
    else
      iter->kindMask |= kind;

    return LoadResult::UpToDate;
  };

  auto interfaceHashCallback = [this, node](StringRef hash) -> LoadResult {
    auto insertResult = InterfaceHashes.insert(std::make_pair(node, hash));

    if (insertResult.second) {
      // Treat a newly-added hash as up-to-date. This includes the initial
      // load of the file.
      return LoadResult::UpToDate;
    }

    auto iter = insertResult.first;
    if (hash != iter->second) {
      iter->second = hash;
      return LoadResult::AffectsDownstream;
    }

    return LoadResult::UpToDate;
  };

  return parseDependencyFile(buffer, providesCallback, dependsCallback,
                             interfaceHashCallback);
}

void DependencyGraphImpl::markExternal(SmallVectorImpl<const void *> &visited,
                                       StringRef externalDependency) {
  auto allDependents = Dependencies.find(externalDependency);
  assert(allDependents != Dependencies.end() && "not a dependency!");
  allDependents->second.second |= DependencyKind::ExternalFile;

  for (const auto &dependent : allDependents->second.first) {
    if (!dependent.kindMask.contains(DependencyKind::ExternalFile))
      continue;
    if (isMarked(dependent.node))
      continue;
    assert(dependent.flags & DependencyFlags::IsCascading);
    visited.push_back(dependent.node);
    markTransitive(visited, dependent.node);
  }
}

void
DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &visited,
                                    const void *node, MarkTracerImpl *tracer) {
  assert(Provides.count(node) && "node is not in the graph");
  llvm::SpecificBumpPtrAllocator<MarkTracerImpl::Entry> scratchAlloc;

  struct WorklistEntry {
    ArrayRef<MarkTracerImpl::Entry> Reason;
    const void *Node;
    bool IsCascading;
  };

  SmallVector<WorklistEntry, 16> worklist;
  SmallPtrSet<const void *, 16> visitedSet;

  auto addDependentsToWorklist = [&](const void *next,
                                     ArrayRef<MarkTracerImpl::Entry> reason) {
    auto allProvided = Provides.find(next);
    if (allProvided == Provides.end())
      return;

    for (const auto &provided : allProvided->second) {
      auto allDependents = Dependencies.find(provided.name);
      if (allDependents == Dependencies.end())
        continue;

      if (allDependents->second.second.contains(provided.kindMask))
        continue;

      // Record that we've traversed this dependency.
      allDependents->second.second |= provided.kindMask;

      for (const auto &dependent : allDependents->second.first) {
        if (dependent.node == next)
          continue;
        auto intersectingKinds = provided.kindMask & dependent.kindMask;
        if (!intersectingKinds)
          continue;
        if (isMarked(dependent.node))
          continue;
        bool isCascading{dependent.flags & DependencyFlags::IsCascading};

        MutableArrayRef<MarkTracerImpl::Entry> newReason;
        if (tracer) {
          newReason = {scratchAlloc.Allocate(reason.size()+1), reason.size()+1};
          std::uninitialized_copy(reason.begin(), reason.end(),
                                  newReason.begin());
          new (&newReason.back()) MarkTracerImpl::Entry({next, provided.name,
                                                         intersectingKinds});
        }
        worklist.push_back({ newReason, dependent.node, isCascading });
      }
    }
  };

  auto record = [&](WorklistEntry next) {
    if (!visitedSet.insert(next.Node).second)
      return;
    visited.push_back(next.Node);
    if (tracer) {
      auto &savedReason = tracer->Table[next.Node];
      savedReason.clear();
      savedReason.append(next.Reason.begin(), next.Reason.end());
    }
  };

  // Always mark through the starting node, even if it's already marked.
  markIntransitive(node);
  addDependentsToWorklist(node, {});

  while (!worklist.empty()) {
    auto next = worklist.pop_back_val();

    // Is this a non-cascading dependency?
    if (!next.IsCascading) {
      if (!isMarked(next.Node))
        record(next);
      continue;
    }

    addDependentsToWorklist(next.Node, next.Reason);
    if (!markIntransitive(next.Node))
      continue;
    record(next);
  }
}

void DependencyGraphImpl::MarkTracerImpl::printPath(
    raw_ostream &out,
    const void *item,
    llvm::function_ref<void (const void *)> printItem) const {
  for (const Entry &entry : Table.lookup(item)) {
    out << "\t";
    printItem(entry.Node);
    if (entry.KindMask.contains(DependencyKind::TopLevelName)) {
      out << " provides top-level name '" << entry.Name << "'\n";

    } else if (entry.KindMask.contains(DependencyKind::NominalType)) {
      SmallString<64> name{entry.Name};
      if (name.front() == 'P')
        name.push_back('_');
      out << " provides type '"
          << swift::Demangle::demangleTypeAsString(name.str())
          << "'\n";

    } else if (entry.KindMask.contains(DependencyKind::NominalTypeMember)) {
      SmallString<64> name{entry.Name};
      size_t splitPoint = name.find('\0');
      assert(splitPoint != StringRef::npos);

      StringRef typePart;
      if (name.front() == 'P') {
        name[splitPoint] = '_';
        typePart = name.str().slice(0, splitPoint+1);
      } else {
        typePart = name.str().slice(0, splitPoint);
      }
      StringRef memberPart = name.str().substr(splitPoint+1);

      out << " provides member '" << memberPart << "' of type '"
          << swift::Demangle::demangleTypeAsString(typePart)
          << "'\n";

    } else if (entry.KindMask.contains(DependencyKind::DynamicLookupName)) {
      out << " provides AnyObject member '" << entry.Name << "'\n";

    } else {
      llvm_unreachable("not a dependency kind between nodes");
    }
  }
}
<commit_msg>[Driver] Differentiate logging of the special "" provided member.<commit_after>//===--- DependencyGraph.cpp - Track intra-module dependencies ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Driver/DependencyGraph.h"
#include "swift/Basic/Demangle.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"

using namespace swift;

enum class DependencyGraphImpl::DependencyKind : uint8_t {
  TopLevelName = 1 << 0,
  DynamicLookupName = 1 << 1,
  NominalType = 1 << 2,
  NominalTypeMember = 1 << 3,
  ExternalFile = 1 << 4,
};
enum class DependencyGraphImpl::DependencyFlags : uint8_t {
  IsCascading = 1 << 0
};

class DependencyGraphImpl::MarkTracerImpl::Entry {
public:
  const void *Node;
  StringRef Name;
  DependencyMaskTy KindMask;
};

DependencyGraphImpl::MarkTracerImpl::MarkTracerImpl() = default;
DependencyGraphImpl::MarkTracerImpl::~MarkTracerImpl() = default;

using LoadResult = DependencyGraphImpl::LoadResult;
using DependencyKind = DependencyGraphImpl::DependencyKind;
using DependencyCallbackTy = LoadResult(StringRef, DependencyKind, bool);
using InterfaceHashCallbackTy = LoadResult(StringRef);

static LoadResult
parseDependencyFile(llvm::MemoryBuffer &buffer,
                    llvm::function_ref<DependencyCallbackTy> providesCallback,
                    llvm::function_ref<DependencyCallbackTy> dependsCallback,
                    llvm::function_ref<InterfaceHashCallbackTy> interfaceHashCallback) {
  namespace yaml = llvm::yaml;

  // FIXME: Switch to a format other than YAML.
  llvm::SourceMgr SM;
  yaml::Stream stream(buffer.getMemBufferRef(), SM);
  auto I = stream.begin();
  if (I == stream.end() || !I->getRoot())
    return LoadResult::HadError;

  auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot());
  if (!topLevelMap) {
    if (isa<yaml::NullNode>(I->getRoot()))
      return LoadResult::UpToDate;
    return LoadResult::HadError;
  }

  LoadResult result = LoadResult::UpToDate;
  SmallString<64> scratch;

  // After an entry, we know more about the node as a whole.
  // Update the "result" variable above.
  // This is a macro rather than a lambda because it contains a return.
#define UPDATE_RESULT(update) switch (update) {\
    case LoadResult::HadError: \
      return LoadResult::HadError; \
    case LoadResult::UpToDate: \
      break; \
    case LoadResult::AffectsDownstream: \
      result = LoadResult::AffectsDownstream; \
      break; \
    } \

  // FIXME: LLVM's YAML support does incremental parsing in such a way that
  // for-range loops break.
  for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) {
    if (isa<yaml::NullNode>(i->getValue()))
      continue;

    auto *key = dyn_cast<yaml::ScalarNode>(i->getKey());
    if (!key)
      return LoadResult::HadError;
    StringRef keyString = key->getValue(scratch);

    if (keyString == "interface-hash") {
      auto *value = dyn_cast<yaml::ScalarNode>(i->getValue());
      if (!value)
        return LoadResult::HadError;

      StringRef valueString = value->getValue(scratch);
      UPDATE_RESULT(interfaceHashCallback(valueString));

    } else {
      enum class DependencyDirection : bool {
        Depends,
        Provides
      };
      using KindPair = std::pair<DependencyKind, DependencyDirection>;

      KindPair dirAndKind = llvm::StringSwitch<KindPair>(key->getValue(scratch))
        .Case("depends-top-level",
              std::make_pair(DependencyKind::TopLevelName,
                             DependencyDirection::Depends))
        .Case("depends-nominal",
              std::make_pair(DependencyKind::NominalType,
                             DependencyDirection::Depends))
        .Case("depends-member",
              std::make_pair(DependencyKind::NominalTypeMember,
                             DependencyDirection::Depends))
        .Case("depends-dynamic-lookup",
              std::make_pair(DependencyKind::DynamicLookupName,
                             DependencyDirection::Depends))
        .Case("depends-external",
              std::make_pair(DependencyKind::ExternalFile,
                             DependencyDirection::Depends))
        .Case("provides-top-level",
              std::make_pair(DependencyKind::TopLevelName,
                             DependencyDirection::Provides))
        .Case("provides-nominal",
              std::make_pair(DependencyKind::NominalType,
                             DependencyDirection::Provides))
        .Case("provides-member",
              std::make_pair(DependencyKind::NominalTypeMember,
                             DependencyDirection::Provides))
        .Case("provides-dynamic-lookup",
              std::make_pair(DependencyKind::DynamicLookupName,
                             DependencyDirection::Provides))
        .Default(std::make_pair(DependencyKind(),
                                DependencyDirection::Depends));
      if (dirAndKind.first == DependencyKind())
        return LoadResult::HadError;

      auto *entries = dyn_cast<yaml::SequenceNode>(i->getValue());
      if (!entries)
        return LoadResult::HadError;

      if (dirAndKind.first == DependencyKind::NominalTypeMember) {
        // Handle member dependencies specially. Rather than being a single
        // string, they come in the form ["{MangledBaseName}", "memberName"].
        for (yaml::Node &rawEntry : *entries) {
          bool isCascading = rawEntry.getRawTag() != "!private";

          auto *entry = dyn_cast<yaml::SequenceNode>(&rawEntry);
          if (!entry)
            return LoadResult::HadError;

          auto iter = entry->begin();
          auto *base = dyn_cast<yaml::ScalarNode>(&*iter);
          if (!base)
            return LoadResult::HadError;
          ++iter;

          auto *member = dyn_cast<yaml::ScalarNode>(&*iter);
          if (!member)
            return LoadResult::HadError;
          ++iter;

          // FIXME: LLVM's YAML support doesn't implement == correctly for end
          // iterators.
          assert(!(iter != entry->end()));

          bool isDepends = dirAndKind.second == DependencyDirection::Depends;
          auto &callback = isDepends ? dependsCallback : providesCallback;

          // Smash the type and member names together so we can continue using
          // StringMap.
          SmallString<64> appended;
          appended += base->getValue(scratch);
          appended.push_back('\0');
          appended += member->getValue(scratch);

          UPDATE_RESULT(callback(appended.str(), dirAndKind.first,
                                 isCascading));
        }
      } else {
        for (const yaml::Node &rawEntry : *entries) {
          auto *entry = dyn_cast<yaml::ScalarNode>(&rawEntry);
          if (!entry)
            return LoadResult::HadError;

          bool isDepends = dirAndKind.second == DependencyDirection::Depends;
          auto &callback = isDepends ? dependsCallback : providesCallback;

          UPDATE_RESULT(callback(entry->getValue(scratch), dirAndKind.first,
                                 entry->getRawTag() != "!private"));
        }
      }
    }
  }

  return result;
}

LoadResult DependencyGraphImpl::loadFromPath(const void *node, StringRef path) {
  auto buffer = llvm::MemoryBuffer::getFile(path);
  if (!buffer)
    return LoadResult::HadError;
  return loadFromBuffer(node, *buffer.get());
}

LoadResult
DependencyGraphImpl::loadFromString(const void *node, StringRef data) {
  auto buffer = llvm::MemoryBuffer::getMemBuffer(data);
  return loadFromBuffer(node, *buffer);
}

LoadResult DependencyGraphImpl::loadFromBuffer(const void *node,
                                               llvm::MemoryBuffer &buffer) {
  auto &provides = Provides[node];

  auto dependsCallback = [this, node](StringRef name, DependencyKind kind,
                                      bool isCascading) -> LoadResult {
    if (kind == DependencyKind::ExternalFile)
      ExternalDependencies.insert(name);

    auto &entries = Dependencies[name];
    auto iter = std::find_if(entries.first.begin(), entries.first.end(),
                             [node](const DependencyEntryTy &entry) -> bool {
      return node == entry.node;
    });

    DependencyFlagsTy flags;
    if (isCascading)
      flags |= DependencyFlags::IsCascading;

    if (iter == entries.first.end()) {
      entries.first.push_back({node, kind, flags});
    } else {
      iter->kindMask |= kind;
      iter->flags |= flags;
    }

    if (isCascading && (entries.second & kind))
      return LoadResult::AffectsDownstream;
    return LoadResult::UpToDate;
  };

  auto providesCallback =
      [this, node, &provides](StringRef name, DependencyKind kind,
                              bool isCascading) -> LoadResult {
    assert(isCascading);
    auto iter = std::find_if(provides.begin(), provides.end(),
                             [name](const ProvidesEntryTy &entry) -> bool {
      return name == entry.name;
    });

    if (iter == provides.end())
      provides.push_back({name, kind});
    else
      iter->kindMask |= kind;

    return LoadResult::UpToDate;
  };

  auto interfaceHashCallback = [this, node](StringRef hash) -> LoadResult {
    auto insertResult = InterfaceHashes.insert(std::make_pair(node, hash));

    if (insertResult.second) {
      // Treat a newly-added hash as up-to-date. This includes the initial
      // load of the file.
      return LoadResult::UpToDate;
    }

    auto iter = insertResult.first;
    if (hash != iter->second) {
      iter->second = hash;
      return LoadResult::AffectsDownstream;
    }

    return LoadResult::UpToDate;
  };

  return parseDependencyFile(buffer, providesCallback, dependsCallback,
                             interfaceHashCallback);
}

void DependencyGraphImpl::markExternal(SmallVectorImpl<const void *> &visited,
                                       StringRef externalDependency) {
  auto allDependents = Dependencies.find(externalDependency);
  assert(allDependents != Dependencies.end() && "not a dependency!");
  allDependents->second.second |= DependencyKind::ExternalFile;

  for (const auto &dependent : allDependents->second.first) {
    if (!dependent.kindMask.contains(DependencyKind::ExternalFile))
      continue;
    if (isMarked(dependent.node))
      continue;
    assert(dependent.flags & DependencyFlags::IsCascading);
    visited.push_back(dependent.node);
    markTransitive(visited, dependent.node);
  }
}

void
DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &visited,
                                    const void *node, MarkTracerImpl *tracer) {
  assert(Provides.count(node) && "node is not in the graph");
  llvm::SpecificBumpPtrAllocator<MarkTracerImpl::Entry> scratchAlloc;

  struct WorklistEntry {
    ArrayRef<MarkTracerImpl::Entry> Reason;
    const void *Node;
    bool IsCascading;
  };

  SmallVector<WorklistEntry, 16> worklist;
  SmallPtrSet<const void *, 16> visitedSet;

  auto addDependentsToWorklist = [&](const void *next,
                                     ArrayRef<MarkTracerImpl::Entry> reason) {
    auto allProvided = Provides.find(next);
    if (allProvided == Provides.end())
      return;

    for (const auto &provided : allProvided->second) {
      auto allDependents = Dependencies.find(provided.name);
      if (allDependents == Dependencies.end())
        continue;

      if (allDependents->second.second.contains(provided.kindMask))
        continue;

      // Record that we've traversed this dependency.
      allDependents->second.second |= provided.kindMask;

      for (const auto &dependent : allDependents->second.first) {
        if (dependent.node == next)
          continue;
        auto intersectingKinds = provided.kindMask & dependent.kindMask;
        if (!intersectingKinds)
          continue;
        if (isMarked(dependent.node))
          continue;
        bool isCascading{dependent.flags & DependencyFlags::IsCascading};

        MutableArrayRef<MarkTracerImpl::Entry> newReason;
        if (tracer) {
          newReason = {scratchAlloc.Allocate(reason.size()+1), reason.size()+1};
          std::uninitialized_copy(reason.begin(), reason.end(),
                                  newReason.begin());
          new (&newReason.back()) MarkTracerImpl::Entry({next, provided.name,
                                                         intersectingKinds});
        }
        worklist.push_back({ newReason, dependent.node, isCascading });
      }
    }
  };

  auto record = [&](WorklistEntry next) {
    if (!visitedSet.insert(next.Node).second)
      return;
    visited.push_back(next.Node);
    if (tracer) {
      auto &savedReason = tracer->Table[next.Node];
      savedReason.clear();
      savedReason.append(next.Reason.begin(), next.Reason.end());
    }
  };

  // Always mark through the starting node, even if it's already marked.
  markIntransitive(node);
  addDependentsToWorklist(node, {});

  while (!worklist.empty()) {
    auto next = worklist.pop_back_val();

    // Is this a non-cascading dependency?
    if (!next.IsCascading) {
      if (!isMarked(next.Node))
        record(next);
      continue;
    }

    addDependentsToWorklist(next.Node, next.Reason);
    if (!markIntransitive(next.Node))
      continue;
    record(next);
  }
}

void DependencyGraphImpl::MarkTracerImpl::printPath(
    raw_ostream &out,
    const void *item,
    llvm::function_ref<void (const void *)> printItem) const {
  for (const Entry &entry : Table.lookup(item)) {
    out << "\t";
    printItem(entry.Node);
    if (entry.KindMask.contains(DependencyKind::TopLevelName)) {
      out << " provides top-level name '" << entry.Name << "'\n";

    } else if (entry.KindMask.contains(DependencyKind::NominalType)) {
      SmallString<64> name{entry.Name};
      if (name.front() == 'P')
        name.push_back('_');
      out << " provides type '"
          << swift::Demangle::demangleTypeAsString(name.str())
          << "'\n";

    } else if (entry.KindMask.contains(DependencyKind::NominalTypeMember)) {
      SmallString<64> name{entry.Name};
      size_t splitPoint = name.find('\0');
      assert(splitPoint != StringRef::npos);

      StringRef typePart;
      if (name.front() == 'P') {
        name[splitPoint] = '_';
        typePart = name.str().slice(0, splitPoint+1);
      } else {
        typePart = name.str().slice(0, splitPoint);
      }
      StringRef memberPart = name.str().substr(splitPoint+1);

      if (memberPart.empty()) {
        out << " provides non-private members of type '"
            << swift::Demangle::demangleTypeAsString(typePart)
            << "'\n";
      } else {
        out << " provides member '" << memberPart << "' of type '"
            << swift::Demangle::demangleTypeAsString(typePart)
            << "'\n";
      }
    } else if (entry.KindMask.contains(DependencyKind::DynamicLookupName)) {
      out << " provides AnyObject member '" << entry.Name << "'\n";

    } else {
      llvm_unreachable("not a dependency kind between nodes");
    }
  }
}
<|endoftext|>


<commit_before>// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
// (C) 2005 Mike Weiblen http://mew.cx/ released under the OSGPL.
// Simple example using GLUT to create an OpenGL window and OSG for rendering.
// Derived from osgGLUTsimple.cpp and osgkeyboardmouse.cpp

#include <osgGA/SimpleViewer>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>

#include <SDL.h>
#include <SDL_events.h>

#include <iostream>

int main( int argc, char **argv )
{
    if (argc<2)
    {
        std::cout << argv[0] <<": requires filename argument." << std::endl;
        return 1;
    }

    // init SDL
    if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
    {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
    if (!loadedModel)
    {
        std::cout << argv[0] <<": No data loaded." << std::endl;
        return 1;
    }

    unsigned int windowWidth = 1280;
    unsigned int windowHeight = 1024;

    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

        // set up the surface to render to
    SDL_Surface* screen = SDL_SetVideoMode(windowWidth, windowHeight, 32, SDL_OPENGL | SDL_FULLSCREEN | SDL_RESIZABLE);
    if ( screen == NULL )
    {
        std::cerr<<"Unable to set "<<windowWidth<<"x"<<windowHeight<<" video: %s\n"<< SDL_GetError()<<std::endl;
        exit(1);
    }

    SDL_EnableUNICODE(1);

    osgGA::SimpleViewer viewer;
    viewer.setSceneData(loadedModel.get());
    viewer.setCameraManipulator(new osgGA::TrackballManipulator);
    viewer.getEventQueue()->windowResize(0, 0, windowWidth, windowHeight );

    bool done = false;
    while( !done )
    {
        SDL_Event event;

        while ( SDL_PollEvent(&event) )
        {
            switch (event.type) {

                case SDL_MOUSEMOTION:
                    viewer.getEventQueue()->mouseMotion(event.motion.x, event.motion.y);
                    break;

                case SDL_MOUSEBUTTONDOWN:
                    viewer.getEventQueue()->mouseButtonPress(event.button.x, event.button.y, event.button.button);
                    break;

                case SDL_MOUSEBUTTONUP:
                    viewer.getEventQueue()->mouseButtonRelease(event.button.x, event.button.y, event.button.button);
                    break;

                case SDL_KEYUP:
                    viewer.getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) event.key.keysym.unicode);

                    if (event.key.keysym.sym==SDLK_ESCAPE) done = true;
                    if (event.key.keysym.sym=='f') SDL_WM_ToggleFullScreen(screen);

                    break;

                case SDL_KEYDOWN:
                    viewer.getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) event.key.keysym.unicode);
                    break;

                case SDL_VIDEORESIZE:
                {
                    viewer.getEventQueue()->windowResize(0, 0, event.resize.w, event.resize.h );

                    std::cout<<"event.resize.w="<<event.resize.w<<"  event.resize.h="<<event.resize.h<<std::endl;
                    break;
                }

                case SDL_QUIT:
                    done = true;
            }
        }

        if (done) continue;

        // draw the new frame
        viewer.frame();

    	// Swap Buffers
        SDL_GL_SwapBuffers();
    }

    return 0;
}

/*EOF*/
<commit_msg>Refactored the SDL example so that the event conversion in done is a seperate method.<commit_after>// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
// (C) 2005 Mike Weiblen http://mew.cx/ released under the OSGPL.
// Simple example using GLUT to create an OpenGL window and OSG for rendering.
// Derived from osgGLUTsimple.cpp and osgkeyboardmouse.cpp

#include <osgGA/SimpleViewer>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>

#include <SDL.h>
#include <SDL_events.h>

#include <iostream>

bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue)
{
    switch (event.type) {

        case SDL_MOUSEMOTION:
            eventQueue.mouseMotion(event.motion.x, event.motion.y);
            return true;

        case SDL_MOUSEBUTTONDOWN:
            eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button);
            return true;

        case SDL_MOUSEBUTTONUP:
            eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button);
            return true;

        case SDL_KEYUP:
            eventQueue.keyRelease( (osgGA::GUIEventAdapter::KeySymbol) event.key.keysym.unicode);
            return true;

        case SDL_KEYDOWN:
            eventQueue.keyPress( (osgGA::GUIEventAdapter::KeySymbol) event.key.keysym.unicode);
            return true;

        case SDL_VIDEORESIZE:
            eventQueue.windowResize(0, 0, event.resize.w, event.resize.h );
            return true;

        default:
            break;
    }
    return false;
}

int main( int argc, char **argv )
{
    if (argc<2)
    {
        std::cout << argv[0] <<": requires filename argument." << std::endl;
        return 1;
    }

    // init SDL
    if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
    {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
    if (!loadedModel)
    {
        std::cout << argv[0] <<": No data loaded." << std::endl;
        return 1;
    }

    unsigned int windowWidth = 1280;
    unsigned int windowHeight = 1024;

    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

        // set up the surface to render to
    SDL_Surface* screen = SDL_SetVideoMode(windowWidth, windowHeight, 32, SDL_OPENGL | SDL_FULLSCREEN | SDL_RESIZABLE);
    if ( screen == NULL )
    {
        std::cerr<<"Unable to set "<<windowWidth<<"x"<<windowHeight<<" video: %s\n"<< SDL_GetError()<<std::endl;
        exit(1);
    }

    SDL_EnableUNICODE(1);

    osgGA::SimpleViewer viewer;
    viewer.setSceneData(loadedModel.get());
    viewer.setCameraManipulator(new osgGA::TrackballManipulator);
    viewer.getEventQueue()->windowResize(0, 0, windowWidth, windowHeight );

    bool done = false;
    while( !done )
    {
        SDL_Event event;

        while ( SDL_PollEvent(&event) )
        {
            // pass the SDL event into the viewers event queue
            convertEvent(event, *viewer.getEventQueue());

            switch (event.type) {

                case SDL_KEYUP:

                    if (event.key.keysym.sym==SDLK_ESCAPE) done = true;
                    if (event.key.keysym.sym=='f') SDL_WM_ToggleFullScreen(screen);

                    break;

                case SDL_QUIT:
                    done = true;
            }
        }

        if (done) continue;

        // draw the new frame
        viewer.frame();

    	// Swap Buffers
        SDL_GL_SwapBuffers();
    }

    return 0;
}

/*EOF*/
<|endoftext|>


<commit_before>// Used for testing, do not use it as an example
#include <iostream>

#include "qpp.h"

int main() {
    using namespace qpp;

    /////////// testing ///////////

    std::cout << "testing...\n";
    QCircuitDescription qcd{3, 3};
    qcd.gate_fan(gt.H).measureV(gt.Id(2), 0, 0);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.measureZ(1, 1);
    qcd.measureV(gt.H, 2, 2);

    QCircuit qc{qcd};
    std::cout << ">> BEGIN CIRCUIT DESCRIPTION\n";
    std::cout << qc.get_circuit_description() << '\n';
    std::cout << ">> END CIRCUIT DESCRIPTION\n\n";

    std::cout << ">> BEGIN RUN\n";
    qc.reset();
    qc.run(true);
    std::cout << qc << '\n';
    std::cout << "psi:\n";
    std::cout << disp(qc.get_psi()) << '\n';
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << "\n";
    std::cout << ">> END RUN\n";

    std::cout << ">> RESET\n";
    qc.reset();
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << "\n";

    std::cout << ">> RUN 2\n";
    qc.run(true, 2);

    std::cout << ">> RESET\n";
    qc.reset();

    std::cout << ">> RUN 0\n";
    qc.run(true, 1);
    std::cout << ">> RUN 1\n";
    qc.run(true, 1);
    std::cout << ">> RUN 2\n";
    qc.run(true, 2);
    std::cout << ">> RUN 2, non-verbose\n";
    qc.run(false, 2);
    std::cout << ">> RUN UNTIL END, verbose\n";
    qc.run(true);
    std::cout << ">> END RUN\n";

    std::cout << qc << '\n';
    std::cout << "psi:\n";
    std::cout << disp(qc.get_psi()) << '\n';
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << ", ";
    std::cout << "ip_: " << qc.get_ip() << "\n\n";

    // std::cout << *qc.get_iter(); // end, throws exception::InvalidIterator()

    std::cout << "measurement count: "
              << qc.get_circuit_description().get_measurement_count() << ", ";
    std::cout << "gate_count: " << qc.get_circuit_description().get_gate_count()
              << ", ";
    std::cout << "total count: "
              << qc.get_circuit_description().get_steps_count() << '\n';

    for (auto&& elem : qcd)
        std::cout << elem << '\n';

    QCircuitDescription a(2, 2);
    a.gate(gt.H, 0);
    std::cout << a << '\n';

    QCircuit q{a};
    q.run(true);
    std::cout << q << '\n';

    std::cout << std::boolalpha << is_iterable<QCircuitDescription>::value;
    std::cout << std::noboolalpha << '\n';
    std::cout << std::boolalpha << is_iterable<IQCircuit>::value;
    std::cout << std::noboolalpha << '\n';
    std::cout << std::boolalpha << is_iterable<QCircuit>::value;
    std::cout << std::noboolalpha << '\n';
}
<commit_msg>Update _test.cpp<commit_after>// Used for testing, do not use it as an example
#include <iostream>

#include "qpp.h"

int main() {
    using namespace qpp;

    /////////// testing ///////////

    std::cout << "testing...\n";
    QCircuitDescription qcd{3, 3};
    qcd.gate_fan(gt.H).measureV(gt.Id(2), 0, 0);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.gate(gt.X, 1);
    qcd.measureZ(1, 1);
    qcd.measureV(gt.H, 2, 2);

    QCircuit qc{qcd};
    std::cout << ">> BEGIN CIRCUIT DESCRIPTION\n";
    std::cout << qc.get_circuit_description() << '\n';
    std::cout << ">> END CIRCUIT DESCRIPTION\n\n";

    std::cout << ">> BEGIN RUN\n";
    qc.reset();
    qc.run(true);
    std::cout << qc << '\n';
    std::cout << "psi:\n";
    std::cout << disp(qc.get_psi()) << '\n';
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << "\n";
    std::cout << ">> END RUN\n";

    std::cout << ">> RESET\n";
    qc.reset();
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << "\n";

    std::cout << ">> RUN 2\n";
    qc.run(true, 2);

    std::cout << ">> RESET\n";
    qc.reset();

    std::cout << ">> RUN 0\n";
    qc.run(true, 1);
    std::cout << ">> RUN 1\n";
    qc.run(true, 1);
    std::cout << ">> RUN 2\n";
    qc.run(true, 2);
    std::cout << ">> RUN 2, non-verbose\n";
    qc.run(false, 2);
    std::cout << ">> RUN UNTIL END, verbose\n";
    qc.run(true);
    std::cout << ">> END RUN\n";

    std::cout << qc << '\n';
    std::cout << "psi:\n";
    std::cout << disp(qc.get_psi()) << '\n';
    std::cout << "m_ip_: " << qc.get_m_ip() << ", ";
    std::cout << "q_ip_: " << qc.get_q_ip() << ", ";
    std::cout << "ip_: " << qc.get_ip() << "\n\n";

    // std::cout << *qc.get_iter(); // end, throws exception::InvalidIterator()

    std::cout << "measurement count: "
              << qc.get_circuit_description().get_measurement_count() << ", ";
    std::cout << "gate_count: " << qc.get_circuit_description().get_gate_count()
              << ", ";
    std::cout << "total count: "
              << qc.get_circuit_description().get_steps_count() << '\n';

    for (auto&& elem : qcd)
        std::cout << elem << '\n';

    QCircuitDescription a(2, 2);
    a.gate(gt.H, 0);
    std::cout << a << '\n';

    QCircuit q{a};
    q.run(true);
    std::cout << q << '\n';

    std::cout << std::boolalpha;
    std::cout << is_iterable<QCircuitDescription>::value << '\n';
    std::cout << is_iterable<IQCircuit>::value << '\n';
    std::cout << is_iterable<QCircuit>::value << '\n' << std::noboolalpha;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2011, Arvid Norberg
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 author 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.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include <boost/tuple/tuple.hpp>
#include <iostream>

#include "test.hpp"
#include "setup_transfer.hpp"

void test_swarm()
{
	using namespace libtorrent;

	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;
	session_proxy p3;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48010, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49010, 50000), "0.0.0.0", 0);
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50010, 51000), "0.0.0.0", 0);

	ses1.set_alert_mask(alert::all_categories);
	ses2.set_alert_mask(alert::all_categories);
	ses3.set_alert_mask(alert::all_categories);

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	settings.choking_algorithm = session_settings::auto_expand_choker;
	settings.upload_rate_limit = rate_limit;
	settings.unchoke_slots_limit = 1;
	ses1.set_settings(settings);

	settings.upload_rate_limit = rate_limit / 10;
	settings.download_rate_limit = rate_limit / 5;
	settings.unchoke_slots_limit = 0;
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, true, "_unchoke");

	session_status st = ses1.status();
	TEST_CHECK(st.allowed_upload_slots == 1);
	for (int i = 0; i < 50; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		st = ses1.status();
		std::cerr << st.allowed_upload_slots << " ";
		if (st.allowed_upload_slots >= 2) break;

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		print_ses_rate(i, &st1, &st2, &st3);

		test_sleep(1000);
	}

	TEST_CHECK(st.allowed_upload_slots >= 2);

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
	p3 = ses3.abort();
}

int test_main()
{
	using namespace libtorrent;

	// in case the previous run was t r catch (std::exception&) {}erminated
	error_code ec;
	remove_all("./tmp1_unchoke", ec);
	remove_all("./tmp2_unchoke", ec);
	remove_all("./tmp3_unchoke", ec);

	test_swarm();

	test_sleep(2000);
	TEST_CHECK(!exists("./tmp1_unchoke/temporary"));
	TEST_CHECK(!exists("./tmp2_unchoke/temporary"));
	TEST_CHECK(!exists("./tmp3_unchoke/temporary"));

	remove_all("./tmp1_unchoke", ec);
	remove_all("./tmp2_unchoke", ec);
	remove_all("./tmp3_unchoke", ec);

	return 0;
}

<commit_msg>minor test_auto_unchoke cleanup<commit_after>/*

Copyright (c) 2011, Arvid Norberg
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 author 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.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include <boost/tuple/tuple.hpp>
#include <iostream>

#include "test.hpp"
#include "setup_transfer.hpp"

void test_swarm()
{
	using namespace libtorrent;

	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;
	session_proxy p3;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48010, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49010, 50000), "0.0.0.0", 0);
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50010, 51000), "0.0.0.0", 0);

	ses1.set_alert_mask(alert::all_categories);
	ses2.set_alert_mask(alert::all_categories);
	ses3.set_alert_mask(alert::all_categories);

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	settings.choking_algorithm = session_settings::auto_expand_choker;
	settings.upload_rate_limit = rate_limit;
	settings.unchoke_slots_limit = 1;
	ses1.set_settings(settings);

	settings.upload_rate_limit = rate_limit / 10;
	settings.download_rate_limit = rate_limit / 5;
	settings.unchoke_slots_limit = 0;
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, true, "_unchoke");

	session_status st = ses1.status();
	TEST_CHECK(st.allowed_upload_slots == 1);
	for (int i = 0; i < 100; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		st = ses1.status();
		fprintf(stderr, "allowed unchoked: %d\n", st.allowed_upload_slots);
		if (st.allowed_upload_slots >= 2) break;

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		print_ses_rate(i, &st1, &st2, &st3);

		test_sleep(100);
	}

	TEST_CHECK(st.allowed_upload_slots >= 2);

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
	p3 = ses3.abort();
}

int test_main()
{
	using namespace libtorrent;

	// in case the previous run was t r catch (std::exception&) {}erminated
	error_code ec;
	remove_all("./tmp1_unchoke", ec);
	remove_all("./tmp2_unchoke", ec);
	remove_all("./tmp3_unchoke", ec);

	test_swarm();

	test_sleep(2000);
	TEST_CHECK(!exists("./tmp1_unchoke/temporary"));
	TEST_CHECK(!exists("./tmp2_unchoke/temporary"));
	TEST_CHECK(!exists("./tmp3_unchoke/temporary"));

	remove_all("./tmp1_unchoke", ec);
	remove_all("./tmp2_unchoke", ec);
	remove_all("./tmp3_unchoke", ec);

	return 0;
}

<|endoftext|>