<commit_before>/**
 * Copyright (c) 2016-2018 mvs developers
 *
 * This file is part of metaverse-explorer.
 *
 * metaverse-explorer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <metaverse/explorer/extensions/commands/startmining.hpp>
#include <metaverse/macros_define.hpp>
#include <metaverse/explorer/dispatch.hpp>
#include <metaverse/explorer/extensions/command_extension_func.hpp>
#include <metaverse/explorer/extensions/exception.hpp>
#include <metaverse/explorer/extensions/base_helper.hpp>

namespace libbitcoin {
namespace explorer {
namespace commands {

/************************ startmining *************************/

console_result startmining::invoke(Json::Value& jv_output,
    libbitcoin::server::server_node& node)
{
    auto& blockchain = node.chain_impl();
    auto& miner = node.miner();

    uint64_t height;
    uint64_t rate;
    std::string difficulty;
    bool is_solo_mining;
    miner.get_state(height, rate, difficulty, is_solo_mining);
    if (is_solo_mining) {
        throw setting_required_exception{"Currently mining, please use command <stopmining> to stop the running mining."};
    }

    auto str_addr = get_address(option_.address, blockchain);
    const auto is_use_pow = (option_.consensus == "pow");
    const auto is_use_pos = (option_.consensus == "pos");
    const auto is_use_dpos = (option_.consensus == "dpos");

    if (!option_.address.empty() && str_addr.empty()) {
        throw argument_legality_exception{"invalid mining did/address " + option_.address};
    }

    if (str_addr.empty()) {
        if (!is_use_pow) {
            throw argument_legality_exception{"mining non-pow blocks must specify a mining address!"};
        }

        Json::Value jv_temp;

        // get new address
        const char* cmds2[]{"getnewaddress", auth_.name.c_str(), auth_.auth.c_str()};

        if (dispatch_command(3, cmds2, jv_temp, node, get_api_version()) != console_result::okay) {
            throw address_generate_exception(jv_temp.asString());
        }

        if (get_api_version() == 1) {
            str_addr = jv_temp.asString();
        }
        else if (get_api_version() == 2) {
            str_addr = jv_temp["addresses"][0].asString();
        }
        else {
            str_addr = jv_temp[0].asString();
        }
    }
    else {
        blockchain.is_account_passwd_valid(auth_.name, auth_.auth);

        if (!blockchain.is_valid_address(str_addr)) {
            throw address_invalid_exception{"invalid address parameter! " + str_addr};
        }

        auto sp_account_address = blockchain.get_account_address(auth_.name, str_addr);
        if (!sp_account_address) {
            throw address_dismatch_account_exception{"target address does not match account. " + str_addr};
        }

        if (is_use_dpos || is_use_pos) {
            const std::string pubkey = sp_account_address->get_pub_key();
            const std::string prikey = sp_account_address->get_prv_key(auth_.auth);
            if (!miner.set_pub_and_pri_key(pubkey, prikey)) {
                throw address_invalid_exception{"invalid address parameter(wrong key)! " + str_addr};
            }
            if (!miner.is_witness()) {
                log::error("Mining")
                    << str_addr
                    << " is not a witness at height "
                    << std::to_string(height);
            }
        }
    }

    bc::wallet::payment_address addr(str_addr);

    if (addr.version() == bc::wallet::payment_address::mainnet_p2sh) { // for multisig address
        throw argument_legality_exception{"script address parameter not allowed!"};
    }

    if (is_use_pow) {
        miner.set_accept_block_version(chain::block_version_pow);
    }
    else if (is_use_pos) {
        miner.set_accept_block_version(chain::block_version_pos);
    }
    else if (is_use_dpos) {
        miner.set_accept_block_version(chain::block_version_dpos);
    }
    else {
#ifdef PRIVATE_CHAIN
        miner.set_accept_block_version(chain::block_version_any);
#else
        throw argument_legality_exception{"wrong consensus of block version!"};
#endif
    }

    // start
    if (miner.start(addr, option_.number)){
        std::string prompt = "solo mining started at "
            + str_addr + ", accept consensus " + option_.consensus;
        if (option_.number == 0) {
            jv_output = prompt;
        } else {
            jv_output = prompt + ", try to mine " + std::to_string(option_.number) + " block(s).";
        }
    }
    else {
        throw unknown_error_exception{"solo mining startup got error"};
    }

    return console_result::okay;
}

} // namespace commands
} // namespace explorer
} // namespace libbitcoin

<commit_msg>for right log<commit_after>/**
 * Copyright (c) 2016-2018 mvs developers
 *
 * This file is part of metaverse-explorer.
 *
 * metaverse-explorer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <metaverse/explorer/extensions/commands/startmining.hpp>
#include <metaverse/macros_define.hpp>
#include <metaverse/explorer/dispatch.hpp>
#include <metaverse/explorer/extensions/command_extension_func.hpp>
#include <metaverse/explorer/extensions/exception.hpp>
#include <metaverse/explorer/extensions/base_helper.hpp>

namespace libbitcoin {
namespace explorer {
namespace commands {

/************************ startmining *************************/

console_result startmining::invoke(Json::Value& jv_output,
    libbitcoin::server::server_node& node)
{
    auto& blockchain = node.chain_impl();
    auto& miner = node.miner();

    uint64_t height;
    uint64_t rate;
    std::string difficulty;
    bool is_solo_mining;
    miner.get_state(height, rate, difficulty, is_solo_mining);
    if (is_solo_mining) {
        throw setting_required_exception{"Currently mining, please use command <stopmining> to stop the running mining."};
    }

    auto str_addr = get_address(option_.address, blockchain);
    const auto is_use_pow = (option_.consensus == "pow");
    const auto is_use_pos = (option_.consensus == "pos");
    const auto is_use_dpos = (option_.consensus == "dpos");

    if (!option_.address.empty() && str_addr.empty()) {
        throw argument_legality_exception{"invalid mining did/address " + option_.address};
    }

    if (str_addr.empty()) {
        if (!is_use_pow) {
            throw argument_legality_exception{"mining non-pow blocks must specify a mining address!"};
        }

        Json::Value jv_temp;

        // get new address
        const char* cmds2[]{"getnewaddress", auth_.name.c_str(), auth_.auth.c_str()};

        if (dispatch_command(3, cmds2, jv_temp, node, get_api_version()) != console_result::okay) {
            throw address_generate_exception(jv_temp.asString());
        }

        if (get_api_version() == 1) {
            str_addr = jv_temp.asString();
        }
        else if (get_api_version() == 2) {
            str_addr = jv_temp["addresses"][0].asString();
        }
        else {
            str_addr = jv_temp[0].asString();
        }
    }
    else {
        blockchain.is_account_passwd_valid(auth_.name, auth_.auth);

        if (!blockchain.is_valid_address(str_addr)) {
            throw address_invalid_exception{"invalid address parameter! " + str_addr};
        }

        auto sp_account_address = blockchain.get_account_address(auth_.name, str_addr);
        if (!sp_account_address) {
            throw address_dismatch_account_exception{"target address does not match account. " + str_addr};
        }

        if (is_use_dpos || is_use_pos) {
            const std::string pubkey = sp_account_address->get_pub_key();
            const std::string prikey = sp_account_address->get_prv_key(auth_.auth);
            if (!miner.set_pub_and_pri_key(pubkey, prikey)) {
                throw address_invalid_exception{"invalid address parameter(wrong key)! " + str_addr};
            }
            if (is_use_dpos && !miner.is_witness()) {
                log::error("Mining")
                    << str_addr
                    << " is not a witness at height "
                    << std::to_string(height);
            }
        }
    }

    bc::wallet::payment_address addr(str_addr);

    if (addr.version() == bc::wallet::payment_address::mainnet_p2sh) { // for multisig address
        throw argument_legality_exception{"script address parameter not allowed!"};
    }

    if (is_use_pow) {
        miner.set_accept_block_version(chain::block_version_pow);
    }
    else if (is_use_pos) {
        miner.set_accept_block_version(chain::block_version_pos);
    }
    else if (is_use_dpos) {
        miner.set_accept_block_version(chain::block_version_dpos);
    }
    else {
#ifdef PRIVATE_CHAIN
        miner.set_accept_block_version(chain::block_version_any);
#else
        throw argument_legality_exception{"wrong consensus of block version!"};
#endif
    }

    // start
    if (miner.start(addr, option_.number)){
        std::string prompt = "solo mining started at "
            + str_addr + ", accept consensus " + option_.consensus;
        if (option_.number == 0) {
            jv_output = prompt;
        } else {
            jv_output = prompt + ", try to mine " + std::to_string(option_.number) + " block(s).";
        }
    }
    else {
        throw unknown_error_exception{"solo mining startup got error"};
    }

    return console_result::okay;
}

} // namespace commands
} // namespace explorer
} // namespace libbitcoin

<|endoftext|>


<commit_before>#include "unicorn/io.hpp"
#include "unicorn/format.hpp"
#include "unicorn/mbcs.hpp"
#include "unicorn/string.hpp"
#include "crow/thread.hpp"
#include <algorithm>
#include <cerrno>

using namespace std::literals;
using namespace Unicorn::Literals;

namespace Unicorn {

    // Exceptions

    u8string IOError::assemble(const char* msg, const u8string& file, int error) {
        auto s = Crow::cstr(msg);
        if (s.empty())
            s = "I/O error";
        if (! file.empty()) {
            s += "; file ";
            if (file.front() == '<' && file.back() == '>')
                s += file;
            else
                format_type(file, s, fx_quote);
        }
        if (error) {
            s += "; error ";
            s += Crow::dec(error);
            string details;
            import_string(system_message(error), details);
            if (! details.empty()) {
                s += "; ";
                s += details;
            }
        }
        return s;
    }

    // I/O implementation

    namespace {

        using SharedFile = std::shared_ptr<FILE>;

        void checked_fclose(FILE* f) {
            if (f)
                fclose(f);
        }

        SharedFile shared_fopen(const NativeString& file, const NativeString& mode, bool check) {
            FILE* f =
                #if defined(_XOPEN_SOURCE)
                    fopen
                #else
                    _wfopen
                #endif
                (file.data(), mode.data());
            if (f || ! check)
                return {f, checked_fclose};
            else if (mode == "rb"_nat)
                throw ReadError(file, errno);
            else
                throw WriteError(file, errno);
        }

    }

    // Simple file I/O

    namespace UnicornDetail {

        void native_load_file(const NativeString& file, string& dst, Crow::Flagset flags) {
            static constexpr size_t bufsize = 65536;
            static const auto dashfile = "-"_nat;
            dst.clear();
            flags.allow(io_stdin | io_nofail, "load file");
            SharedFile handle;
            if (flags.get(io_stdin) && (file.empty() || file == dashfile))
                handle.reset(stdin, Crow::no_delete);
            else
                handle = shared_fopen(file, "rb"_nat, ! flags.get(io_nofail));
            if (! handle)
                return;
            string buf(bufsize, 0);
            while (! feof(handle.get())) {
                auto rc = fread(&buf[0], 1, bufsize, handle.get());
                auto err = errno;
                if (ferror(handle.get()))
                    throw ReadError(file, err);
                dst.append(buf, 0, rc);
            }
        }

        void native_save_file(const NativeString& file, const void* ptr, size_t n, Crow::Flagset flags) {
            static const auto dashfile = "-"_nat;
            flags.allow(io_append | io_stderr | io_stdout, "save file");
            flags.exclusive(io_stderr | io_stdout, "save file");
            SharedFile handle;
            if (flags.get(io_stdout) && (file.empty() || file == dashfile))
                handle.reset(stdout, Crow::no_delete);
            else if (flags.get(io_stderr) && (file.empty() || file == dashfile))
                handle.reset(stderr, Crow::no_delete);
            else
                handle = shared_fopen(file, flags.get(io_append) ? "ab"_nat : "wb"_nat, true);
            fwrite(ptr, 1, n, handle.get());
            auto err = errno;
            if (ferror(handle.get()))
                throw WriteError(file, err);
        }

    }

    // Class FileReader

    struct FileReader::impl_type {
        u8string line8;
        string rdbuf;
        NativeString name;
        Crow::Flagset flags;
        u8string enc;
        u8string eol;
        SharedFile handle;
        bool is_ready() noexcept {
            return handle.get() && ! ferror(handle.get()) && ! feof(handle.get());
        }
    };

    const u8string& FileReader::operator*() const noexcept {
        static const u8string dummy;
        return impl ? impl->line8 : dummy;
    }

    FileReader& FileReader::operator++() {
        do getline();
            while (impl && impl->flags.get(io_notempty)
                && std::all_of(utf_begin(impl->line8), utf_end(impl->line8), char_is_line_break));
        return *this;
    }

    void FileReader::init(const NativeString& file, Crow::Flagset flags, const u8string& enc, const u8string& eol) {
        static const auto dashfile = "-"_nat;
        flags.allow(err_replace | err_throw | io_bom | io_crlf | io_lf
            | io_nofail | io_notempty | io_stdin | io_striplf | io_striptws
            | io_stripws, "file input");
        flags.exclusive(err_replace | err_throw, "file input");
        flags.exclusive(io_crlf | io_lf | io_striplf | io_striptws | io_stripws, "file input");
        impl = std::make_shared<impl_type>();
        impl->name = file;
        impl->flags = flags;
        impl->enc = enc;
        impl->eol = eol;
        if (enc.empty() || enc == "0")
            impl->enc = "utf-8";
        if (flags.get(io_stdin) && (file.empty() || file == dashfile))
            impl->handle.reset(stdin, Crow::no_delete);
        else
            impl->handle = shared_fopen(file, "rb"_nat, ! flags.get(io_nofail));
        ++*this;
    }

    void FileReader::fixline() {
        if (impl->flags.get(io_bom)) {
            if (str_first_char(impl->line8) == byte_order_mark)
                impl->line8.erase(0, utf_begin(impl->line8).count());
            impl->flags.set(io_bom, false);
        }
        if (impl->flags.get(io_lf))
            impl->line8 += '\n';
        else if (impl->flags.get(io_crlf))
            impl->line8 += "\r\n";
        else if (impl->flags.get(io_striptws))
            impl->line8 = str_trim_right(impl->line8);
        else if (impl->flags.get(io_stripws))
            impl->line8 = str_trim(impl->line8);
    }

    void FileReader::getline() {
        if (! impl)
            return;
        impl->line8.clear();
        size_t eolpos = npos, eolbytes = 0, eolsize = impl->eol.size();
        for (;;) {
            if (eolsize) {
                if (eolpos == npos)
                    eolpos = impl->rdbuf.find(impl->eol);
                if (eolpos != npos && (eolpos + eolsize < impl->rdbuf.size() || ! impl->is_ready()))
                    eolbytes = eolsize;
            } else {
                if (eolpos == npos)
                    eolpos = impl->rdbuf.find_first_of("\n\f\r");
                if (eolpos != npos) {
                    if (impl->rdbuf[eolpos] != '\r')
                        eolbytes = 1;
                    else if (impl->rdbuf.size() - eolpos >= 2 || ! impl->is_ready())
                        eolbytes = impl->rdbuf[eolpos + 1] == '\n' ? 2 : 1;
                }
            }
            if (eolbytes > 0 || ! impl->is_ready())
                break;
            getmore(256);
        }
        if (impl->rdbuf.empty()) {
            impl.reset();
            return;
        }
        string encoded(impl->rdbuf, 0, eolpos + eolbytes);
        impl->rdbuf.erase(0, eolpos + eolbytes);
        if (impl->flags.get(io_lf | io_crlf | io_striplf | io_striptws | io_stripws))
            encoded.resize(eolpos);
        import_string(encoded, impl->line8, impl->enc, impl->flags & (err_replace | err_throw));
        fixline();
    }

    void FileReader::getmore(size_t n) {
        if (! impl || n == 0)
            return;
        auto offset = impl->rdbuf.size();
        impl->rdbuf.resize(offset + n);
        auto rc = fread(&impl->rdbuf[offset], 1, n, impl->handle.get());
        auto err = errno;
        impl->rdbuf.resize(offset + rc);
        if (ferror(impl->handle.get()))
            throw ReadError(impl->name, err);
    }

    // Class FileWriter

    struct FileWriter::impl_type {
        u8string wrbuf;
        NativeString name;
        Crow::Flagset flags;
        u8string enc;
        SharedFile handle;
        std::shared_ptr<Crow::Mutex> mutex;
    };

    void FileWriter::flush() {
        if (! impl)
            throw WriteError();
        if (fflush(impl->handle.get()) == EOF)
            throw WriteError(impl->name, errno);
    }

    void FileWriter::init(const NativeString& file, Crow::Flagset flags, const u8string& enc) {
        static const NativeString dashfile{NativeCharacter('-')};
        static Crow::Mutex stdout_mutex;
        static Crow::Mutex stderr_mutex;
        flags.allow(err_replace | err_throw | io_append | io_autoline | io_bom
            | io_crlf | io_lf | io_linebuf | io_mutex | io_stderr
            | io_stdout | io_unbuf | io_writeline, "file output");
        flags.exclusive(err_replace | err_throw, "file output");
        flags.exclusive(io_autoline | io_writeline, "file output");
        flags.exclusive(io_crlf | io_lf, "file output");
        flags.exclusive(io_linebuf | io_unbuf, "file output");
        flags.exclusive(io_stderr | io_stdout, "file output");
        impl = std::make_shared<impl_type>();
        impl->name = file;
        impl->flags = flags;
        impl->enc = enc;
        if (enc.empty() || enc == "0")
            impl->enc = "utf-8";
        if (flags.get(io_stdout) && (file.empty() || file == dashfile))
            impl->handle.reset(stdout, Crow::no_delete);
        else if (flags.get(io_stderr) && (file.empty() || file == dashfile))
            impl->handle.reset(stderr, Crow::no_delete);
        else
            impl->handle = shared_fopen(file, flags.get(io_append) ? "ab"_nat : "wb"_nat, true);
        if (flags.get(io_mutex)) {
            if (impl->handle.get() == stdout)
                impl->mutex.reset(&stdout_mutex, Crow::no_delete);
            else if (impl->handle.get() == stderr)
                impl->mutex.reset(&stderr_mutex, Crow::no_delete);
            else
                impl->mutex = std::make_shared<Crow::Mutex>();
        }
    }

    void FileWriter::fixtext(u8string& str) const {
        if (impl->flags.get(io_writeline) || (impl->flags.get(io_autoline)
                && (str.empty() || ! char_is_line_break(str_last_char(str)))))
            str += '\n';
        if (impl->flags.get(io_lf | io_crlf)) {
            u8string brk = impl->flags.get(io_crlf) ? "\r\n"s : "\n"s;
            auto i = utf_begin(str);
            while (i.offset() < str.size()) {
                if (*i == '\r' && str[i.offset() + 1] == '\n')
                    i = str_change_in(str, i, std::next(std::next(i)), brk).second;
                else if (char_is_line_break(*i))
                    i = str_change_in(str, i, std::next(i), brk).second;
                else
                    ++i;
            }
        }
    }

    void FileWriter::write(u8string str) {
        if (! impl)
            throw WriteError();
        fixtext(str);
        if (impl->flags.get(io_linebuf)) {
            str.insert(0, impl->wrbuf);
            impl->wrbuf.clear();
            auto b = utf_begin(str), e = utf_end(str), i = e;
            while (i != b) {
                --i;
                if (char_is_line_break(*i)) {
                    ++i;
                    break;
                }
            }
            if (i == b) {
                impl->wrbuf.swap(str);
            } else {
                impl->wrbuf = u_str(i, e);
                str.resize(i.offset());
            }
        }
        if (! str.empty()) {
            if (impl->flags.get(io_bom)) {
                if (str_first_char(str) != byte_order_mark)
                    str.insert(0, utf8_bom);
                impl->flags.set(io_bom, false);
            }
            string encoded;
            export_string(str, encoded, impl->enc, impl->flags & (err_replace | err_throw));
            if (impl->mutex) {
                Crow::MutexLock lock(*impl->mutex);
                writembcs(encoded);
            } else {
                writembcs(encoded);
            }
        }
    }

    void FileWriter::writembcs(const string& str) {
        fwrite(str.data(), 1, str.size(), impl->handle.get());
        auto err = errno;
        if (ferror(impl->handle.get()))
            throw WriteError(impl->name, err);
        if (impl->flags.get(io_linebuf | io_unbuf))
            flush();
    }

}
<commit_msg>Change no_delete to do_nothing<commit_after>#include "unicorn/io.hpp"
#include "unicorn/format.hpp"
#include "unicorn/mbcs.hpp"
#include "unicorn/string.hpp"
#include "crow/thread.hpp"
#include <algorithm>
#include <cerrno>

using namespace std::literals;
using namespace Unicorn::Literals;

namespace Unicorn {

    // Exceptions

    u8string IOError::assemble(const char* msg, const u8string& file, int error) {
        auto s = Crow::cstr(msg);
        if (s.empty())
            s = "I/O error";
        if (! file.empty()) {
            s += "; file ";
            if (file.front() == '<' && file.back() == '>')
                s += file;
            else
                format_type(file, s, fx_quote);
        }
        if (error) {
            s += "; error ";
            s += Crow::dec(error);
            string details;
            import_string(system_message(error), details);
            if (! details.empty()) {
                s += "; ";
                s += details;
            }
        }
        return s;
    }

    // I/O implementation

    namespace {

        using SharedFile = std::shared_ptr<FILE>;

        void checked_fclose(FILE* f) {
            if (f)
                fclose(f);
        }

        SharedFile shared_fopen(const NativeString& file, const NativeString& mode, bool check) {
            FILE* f =
                #if defined(_XOPEN_SOURCE)
                    fopen
                #else
                    _wfopen
                #endif
                (file.data(), mode.data());
            if (f || ! check)
                return {f, checked_fclose};
            else if (mode == "rb"_nat)
                throw ReadError(file, errno);
            else
                throw WriteError(file, errno);
        }

    }

    // Simple file I/O

    namespace UnicornDetail {

        void native_load_file(const NativeString& file, string& dst, Crow::Flagset flags) {
            static constexpr size_t bufsize = 65536;
            static const auto dashfile = "-"_nat;
            dst.clear();
            flags.allow(io_stdin | io_nofail, "load file");
            SharedFile handle;
            if (flags.get(io_stdin) && (file.empty() || file == dashfile))
                handle.reset(stdin, Crow::do_nothing);
            else
                handle = shared_fopen(file, "rb"_nat, ! flags.get(io_nofail));
            if (! handle)
                return;
            string buf(bufsize, 0);
            while (! feof(handle.get())) {
                auto rc = fread(&buf[0], 1, bufsize, handle.get());
                auto err = errno;
                if (ferror(handle.get()))
                    throw ReadError(file, err);
                dst.append(buf, 0, rc);
            }
        }

        void native_save_file(const NativeString& file, const void* ptr, size_t n, Crow::Flagset flags) {
            static const auto dashfile = "-"_nat;
            flags.allow(io_append | io_stderr | io_stdout, "save file");
            flags.exclusive(io_stderr | io_stdout, "save file");
            SharedFile handle;
            if (flags.get(io_stdout) && (file.empty() || file == dashfile))
                handle.reset(stdout, Crow::do_nothing);
            else if (flags.get(io_stderr) && (file.empty() || file == dashfile))
                handle.reset(stderr, Crow::do_nothing);
            else
                handle = shared_fopen(file, flags.get(io_append) ? "ab"_nat : "wb"_nat, true);
            fwrite(ptr, 1, n, handle.get());
            auto err = errno;
            if (ferror(handle.get()))
                throw WriteError(file, err);
        }

    }

    // Class FileReader

    struct FileReader::impl_type {
        u8string line8;
        string rdbuf;
        NativeString name;
        Crow::Flagset flags;
        u8string enc;
        u8string eol;
        SharedFile handle;
        bool is_ready() noexcept {
            return handle.get() && ! ferror(handle.get()) && ! feof(handle.get());
        }
    };

    const u8string& FileReader::operator*() const noexcept {
        static const u8string dummy;
        return impl ? impl->line8 : dummy;
    }

    FileReader& FileReader::operator++() {
        do getline();
            while (impl && impl->flags.get(io_notempty)
                && std::all_of(utf_begin(impl->line8), utf_end(impl->line8), char_is_line_break));
        return *this;
    }

    void FileReader::init(const NativeString& file, Crow::Flagset flags, const u8string& enc, const u8string& eol) {
        static const auto dashfile = "-"_nat;
        flags.allow(err_replace | err_throw | io_bom | io_crlf | io_lf
            | io_nofail | io_notempty | io_stdin | io_striplf | io_striptws
            | io_stripws, "file input");
        flags.exclusive(err_replace | err_throw, "file input");
        flags.exclusive(io_crlf | io_lf | io_striplf | io_striptws | io_stripws, "file input");
        impl = std::make_shared<impl_type>();
        impl->name = file;
        impl->flags = flags;
        impl->enc = enc;
        impl->eol = eol;
        if (enc.empty() || enc == "0")
            impl->enc = "utf-8";
        if (flags.get(io_stdin) && (file.empty() || file == dashfile))
            impl->handle.reset(stdin, Crow::do_nothing);
        else
            impl->handle = shared_fopen(file, "rb"_nat, ! flags.get(io_nofail));
        ++*this;
    }

    void FileReader::fixline() {
        if (impl->flags.get(io_bom)) {
            if (str_first_char(impl->line8) == byte_order_mark)
                impl->line8.erase(0, utf_begin(impl->line8).count());
            impl->flags.set(io_bom, false);
        }
        if (impl->flags.get(io_lf))
            impl->line8 += '\n';
        else if (impl->flags.get(io_crlf))
            impl->line8 += "\r\n";
        else if (impl->flags.get(io_striptws))
            impl->line8 = str_trim_right(impl->line8);
        else if (impl->flags.get(io_stripws))
            impl->line8 = str_trim(impl->line8);
    }

    void FileReader::getline() {
        if (! impl)
            return;
        impl->line8.clear();
        size_t eolpos = npos, eolbytes = 0, eolsize = impl->eol.size();
        for (;;) {
            if (eolsize) {
                if (eolpos == npos)
                    eolpos = impl->rdbuf.find(impl->eol);
                if (eolpos != npos && (eolpos + eolsize < impl->rdbuf.size() || ! impl->is_ready()))
                    eolbytes = eolsize;
            } else {
                if (eolpos == npos)
                    eolpos = impl->rdbuf.find_first_of("\n\f\r");
                if (eolpos != npos) {
                    if (impl->rdbuf[eolpos] != '\r')
                        eolbytes = 1;
                    else if (impl->rdbuf.size() - eolpos >= 2 || ! impl->is_ready())
                        eolbytes = impl->rdbuf[eolpos + 1] == '\n' ? 2 : 1;
                }
            }
            if (eolbytes > 0 || ! impl->is_ready())
                break;
            getmore(256);
        }
        if (impl->rdbuf.empty()) {
            impl.reset();
            return;
        }
        string encoded(impl->rdbuf, 0, eolpos + eolbytes);
        impl->rdbuf.erase(0, eolpos + eolbytes);
        if (impl->flags.get(io_lf | io_crlf | io_striplf | io_striptws | io_stripws))
            encoded.resize(eolpos);
        import_string(encoded, impl->line8, impl->enc, impl->flags & (err_replace | err_throw));
        fixline();
    }

    void FileReader::getmore(size_t n) {
        if (! impl || n == 0)
            return;
        auto offset = impl->rdbuf.size();
        impl->rdbuf.resize(offset + n);
        auto rc = fread(&impl->rdbuf[offset], 1, n, impl->handle.get());
        auto err = errno;
        impl->rdbuf.resize(offset + rc);
        if (ferror(impl->handle.get()))
            throw ReadError(impl->name, err);
    }

    // Class FileWriter

    struct FileWriter::impl_type {
        u8string wrbuf;
        NativeString name;
        Crow::Flagset flags;
        u8string enc;
        SharedFile handle;
        std::shared_ptr<Crow::Mutex> mutex;
    };

    void FileWriter::flush() {
        if (! impl)
            throw WriteError();
        if (fflush(impl->handle.get()) == EOF)
            throw WriteError(impl->name, errno);
    }

    void FileWriter::init(const NativeString& file, Crow::Flagset flags, const u8string& enc) {
        static const NativeString dashfile{NativeCharacter('-')};
        static Crow::Mutex stdout_mutex;
        static Crow::Mutex stderr_mutex;
        flags.allow(err_replace | err_throw | io_append | io_autoline | io_bom
            | io_crlf | io_lf | io_linebuf | io_mutex | io_stderr
            | io_stdout | io_unbuf | io_writeline, "file output");
        flags.exclusive(err_replace | err_throw, "file output");
        flags.exclusive(io_autoline | io_writeline, "file output");
        flags.exclusive(io_crlf | io_lf, "file output");
        flags.exclusive(io_linebuf | io_unbuf, "file output");
        flags.exclusive(io_stderr | io_stdout, "file output");
        impl = std::make_shared<impl_type>();
        impl->name = file;
        impl->flags = flags;
        impl->enc = enc;
        if (enc.empty() || enc == "0")
            impl->enc = "utf-8";
        if (flags.get(io_stdout) && (file.empty() || file == dashfile))
            impl->handle.reset(stdout, Crow::do_nothing);
        else if (flags.get(io_stderr) && (file.empty() || file == dashfile))
            impl->handle.reset(stderr, Crow::do_nothing);
        else
            impl->handle = shared_fopen(file, flags.get(io_append) ? "ab"_nat : "wb"_nat, true);
        if (flags.get(io_mutex)) {
            if (impl->handle.get() == stdout)
                impl->mutex.reset(&stdout_mutex, Crow::do_nothing);
            else if (impl->handle.get() == stderr)
                impl->mutex.reset(&stderr_mutex, Crow::do_nothing);
            else
                impl->mutex = std::make_shared<Crow::Mutex>();
        }
    }

    void FileWriter::fixtext(u8string& str) const {
        if (impl->flags.get(io_writeline) || (impl->flags.get(io_autoline)
                && (str.empty() || ! char_is_line_break(str_last_char(str)))))
            str += '\n';
        if (impl->flags.get(io_lf | io_crlf)) {
            u8string brk = impl->flags.get(io_crlf) ? "\r\n"s : "\n"s;
            auto i = utf_begin(str);
            while (i.offset() < str.size()) {
                if (*i == '\r' && str[i.offset() + 1] == '\n')
                    i = str_change_in(str, i, std::next(std::next(i)), brk).second;
                else if (char_is_line_break(*i))
                    i = str_change_in(str, i, std::next(i), brk).second;
                else
                    ++i;
            }
        }
    }

    void FileWriter::write(u8string str) {
        if (! impl)
            throw WriteError();
        fixtext(str);
        if (impl->flags.get(io_linebuf)) {
            str.insert(0, impl->wrbuf);
            impl->wrbuf.clear();
            auto b = utf_begin(str), e = utf_end(str), i = e;
            while (i != b) {
                --i;
                if (char_is_line_break(*i)) {
                    ++i;
                    break;
                }
            }
            if (i == b) {
                impl->wrbuf.swap(str);
            } else {
                impl->wrbuf = u_str(i, e);
                str.resize(i.offset());
            }
        }
        if (! str.empty()) {
            if (impl->flags.get(io_bom)) {
                if (str_first_char(str) != byte_order_mark)
                    str.insert(0, utf8_bom);
                impl->flags.set(io_bom, false);
            }
            string encoded;
            export_string(str, encoded, impl->enc, impl->flags & (err_replace | err_throw));
            if (impl->mutex) {
                Crow::MutexLock lock(*impl->mutex);
                writembcs(encoded);
            } else {
                writembcs(encoded);
            }
        }
    }

    void FileWriter::writembcs(const string& str) {
        fwrite(str.data(), 1, str.size(), impl->handle.get());
        auto err = errno;
        if (ferror(impl->handle.get()))
            throw WriteError(impl->name, err);
        if (impl->flags.get(io_linebuf | io_unbuf))
            flush();
    }

}
<|endoftext|>


<commit_before>// RUN: cat %s | %cling -Xclang -verify
// This test verifies that we get nice warning if a method on null ptr object is
// called.
// XFAIL:*
extern "C" int printf(const char* fmt, ...);
class MyClass {
private:
  int a;
public:
  MyClass() : a(1){}
  int getA(){return a;}
};
MyClass* my = 0;
my->getA() // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}
.q
<commit_msg>Add another expected to pass construct for null deref.<commit_after>// RUN: cat %s | %cling -Xclang -verify
// This test verifies that we get nice warning if a method on null ptr object is
// called.
// XFAIL:*
extern "C" int printf(const char* fmt, ...);
class MyClass {
private:
  int a;
public:
  MyClass() : a(1){}
  int getA(){return a;}
};
MyClass* my = 0;
my->getA() // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}

struct AggregatedNull {
  AggregatedNull() : m(0) {}
  MyClass m;
}

AggregatedNull agrNull;
agrNull.m->getA(); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}

.q
<|endoftext|>


<commit_before>/*
 * Arduino library to provide a software emulation of a transparent
 * serial link using the RFM12B radio module.
 *
 * Copyright S R Marple, 2013.
 * Released under MIT License, http://opensource.org/licenses/mit-license.php
 */

//#include <util/atomic.h>
#include "Arduino.h"

#include <RF12.h>
#include "RF12_Stream.h"

uint8_t RF12_Stream::packetDataLength = 30;
unsigned long RF12_Stream::retryDelay_ms = 50;
unsigned long RF12_Stream::txDelay_ms = 100;
unsigned long RF12_Stream::flushTimeout_ms = 1000;
uint8_t RF12_Stream::maxRetriesPerPacket = 3;
uint32_t RF12_Stream::retries = 0;
uint32_t RF12_Stream::rxPackets = 0;
uint32_t RF12_Stream::txPackets = 0;

volatile bool RF12_Stream::isPresent = false;

RF12_Stream::RF12_Stream(void *rxBuffer, int rxBufferLen,
		void *txBuffer, int txBufferLen)
  : rxNum(-1),
    txNum(0),
    ackNum(0),
    sendAck(false),
    txBytesPending(0),
    packetTries(0),
    //rxBuf(rxBuffer, rxBufferLen, true, false),
    //txBuf(txBuffer, txBufferLen, true, false)
    rxBuf(rxBuffer, rxBufferLen),
    txBuf(txBuffer, txBufferLen)
{
  ;
}

bool RF12_Stream::begin(uint8_t cs, uint8_t irqPin, uint8_t irqNum,
			uint8_t id, uint8_t band, uint8_t group)
{
  pinMode(cs, OUTPUT);
  pinMode(irqPin, INPUT);
  rf12_set_cs(cs);
  rf12_set_irq(irqPin, irqNum);
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    rf12_initialize(id, band, group);
  //}

  // Check RFM12B is present. Use our own interrupt handler to respond
  // to a software reset.
  attachInterrupt(irqNum, RF12_Stream::detectHandler, LOW);
  rf12_control(0xCA82); // Set up sensitive reset mode
  rf12_control(0xFE00); // Software reset

  AsyncDelay detectTimeout;
  detectTimeout.start(100, AsyncDelay::MILLIS);
  while (!detectTimeout.isExpired() && !isPresent)
    ; // Loop

  // Restore settings
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    rf12_initialize(id, band, group);
  // }
  return isPresent;
}

void RF12_Stream::poll(void)
{
  // Check for received packet
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    if (rf12_recvDone() && rf12_crc == 0) {
      if ((rf12_hdr & RF12_HDR_CTL) && rf12_len == sizeof(txNum)) {
	// ACK received
	uint16_t recdAckNum = (rf12_data[0] << 8) | rf12_data[1];
	if (recdAckNum == txNum) {
	  txBuf.skip(txBytesPending);
	  txBytesPending = 0;
	  packetTries = 0;
	  ++txNum;
	}
      }
      else if ((rf12_hdr & RF12_HDR_CTL) == 0 && rf12_len > sizeof(txNum) &&
	       rf12_len <= (packetDataLength + sizeof(txNum))) {
	// Data
	ackNum = (rf12_data[0] << 8) | rf12_data[1];
	// sendAck = true;
	if (rxNum != ackNum) {
	  rxNum = ackNum;
	  rxBuf.write((const uint8_t*) rf12_data + 2, rf12_len - 2);
	  ++rxPackets;
	}

	// if (sendAck) {
	if (RF12_WANTS_ACK) {
	  uint8_t ackData[sizeof(ackNum)];
	  ackData[1] = ackNum & 0xFF;
	  ackData[0] = (ackNum >> 8) & 0xFF;
	  rf12_sendStart(RF12_ACK_REPLY, ackData, sizeof(ackData));
	}
      }

    }

    if (packetTries > maxRetriesPerPacket && retryDelay.isExpired()) {
      // Enough tries on this portion of data
      txBuf.skip(txBytesPending);
      txBytesPending = 0;
      packetTries = 0;
      ++txNum;
    }

    // Check if data to send.
    // txBytesPending == 0 means no unacknowledged data
    if ((txBytesPending == 0 || retryDelay.isExpired()) &&
	txDelay.isExpired() &&
	txBuf.getSize() && rf12_canSend()) {
      if (packetTries > 1)
	++retries;
      else
	++txPackets;

      ++packetTries;
      uint8_t message[sizeof(txNum) + packetDataLength];
      // First two bytes are the TX packet number, sent in network order
      message[1] = txNum & 0xFF;
      message[0] = (txNum >> 8) & 0xFF;
      txBytesPending = txBuf.peek(message+sizeof(txNum), packetDataLength);
      uint8_t hdr = RF12_HDR_ACK; // RF12_HDR_DST | 0x02;
      rf12_sendStart(hdr, message, sizeof(txNum) + txBytesPending);
      retryDelay.start(retryDelay_ms, AsyncDelay::MILLIS);
    }
  //}
}

int RF12_Stream::available(void)
{
  return rxBuf.getSize();
}

int RF12_Stream::peek(void)
{
  uint8_t c;
  if (rxBuf.peek(&c, sizeof(c)))
    return c;
  else
    return -1;
}

int RF12_Stream::read(void)
{
  uint8_t c;
  if (rxBuf.read(&c, sizeof(c)))
    return c;
  else
    return -1;
}

void RF12_Stream::flush()
{
  // Expire the TX timer and wait for any existing data to be
  // sent. Use timer to prevent lockups.
  txDelay.expire();
  AsyncDelay flushTimeout(flushTimeout_ms, AsyncDelay::MILLIS);
  while (txBytesPending && txBuf.getSize() && !flushTimeout.isExpired())
    poll();
  txBuf.clear();
}

size_t RF12_Stream::write(uint8_t c)
{
  size_t bytesWritten;
  int initialSize = txBuf.getSize();
  bytesWritten = txBuf.write(&c, sizeof(c));
  if (initialSize == 0 && bytesWritten)
    // Start the TX timer when the first character to be sent is received.
    txDelay.start(txDelay_ms, AsyncDelay::MILLIS);
  return bytesWritten;
}

bool RF12_Stream::powerOn(void)
{
  rf12_sleep(RF12_WAKEUP);
  return true;
}

bool RF12_Stream::powerOff(void)
{
  if (txBuf.getSize() && !txDelay.isExpired())
    return false; // Wait for TX buffer to be sent
  rf12_sleep(RF12_SLEEP);
  return true;
}

void RF12_Stream::detectHandler(void)
{
  if (rf12_control(0x0000) & 0x4000)
    isPresent = true;
}
<commit_msg>Clearing RX and TX buffers when powering on/off.<commit_after>/*
 * Arduino library to provide a software emulation of a transparent
 * serial link using the RFM12B radio module.
 *
 * Copyright S R Marple, 2013.
 * Released under MIT License, http://opensource.org/licenses/mit-license.php
 */

//#include <util/atomic.h>
#include "Arduino.h"

#include <RF12.h>
#include "RF12_Stream.h"

uint8_t RF12_Stream::packetDataLength = 30;
unsigned long RF12_Stream::retryDelay_ms = 50;
unsigned long RF12_Stream::txDelay_ms = 100;
unsigned long RF12_Stream::flushTimeout_ms = 1000;
uint8_t RF12_Stream::maxRetriesPerPacket = 3;
uint32_t RF12_Stream::retries = 0;
uint32_t RF12_Stream::rxPackets = 0;
uint32_t RF12_Stream::txPackets = 0;

volatile bool RF12_Stream::isPresent = false;

RF12_Stream::RF12_Stream(void *rxBuffer, int rxBufferLen,
		void *txBuffer, int txBufferLen)
  : rxNum(-1),
    txNum(0),
    ackNum(0),
    sendAck(false),
    txBytesPending(0),
    packetTries(0),
    //rxBuf(rxBuffer, rxBufferLen, true, false),
    //txBuf(txBuffer, txBufferLen, true, false)
    rxBuf(rxBuffer, rxBufferLen),
    txBuf(txBuffer, txBufferLen)
{
  ;
}

bool RF12_Stream::begin(uint8_t cs, uint8_t irqPin, uint8_t irqNum,
			uint8_t id, uint8_t band, uint8_t group)
{
  pinMode(cs, OUTPUT);
  pinMode(irqPin, INPUT);
  rf12_set_cs(cs);
  rf12_set_irq(irqPin, irqNum);
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    rf12_initialize(id, band, group);
  //}

  // Check RFM12B is present. Use our own interrupt handler to respond
  // to a software reset.
  attachInterrupt(irqNum, RF12_Stream::detectHandler, LOW);
  rf12_control(0xCA82); // Set up sensitive reset mode
  rf12_control(0xFE00); // Software reset

  AsyncDelay detectTimeout;
  detectTimeout.start(100, AsyncDelay::MILLIS);
  while (!detectTimeout.isExpired() && !isPresent)
    ; // Loop

  // Restore settings
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    rf12_initialize(id, band, group);
  // }
  return isPresent;
}

void RF12_Stream::poll(void)
{
  // Check for received packet
  //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    if (rf12_recvDone() && rf12_crc == 0) {
      if ((rf12_hdr & RF12_HDR_CTL) && rf12_len == sizeof(txNum)) {
	// ACK received
	uint16_t recdAckNum = (rf12_data[0] << 8) | rf12_data[1];
	if (recdAckNum == txNum) {
	  txBuf.skip(txBytesPending);
	  txBytesPending = 0;
	  packetTries = 0;
	  ++txNum;
	}
      }
      else if ((rf12_hdr & RF12_HDR_CTL) == 0 && rf12_len > sizeof(txNum) &&
	       rf12_len <= (packetDataLength + sizeof(txNum))) {
	// Data
	ackNum = (rf12_data[0] << 8) | rf12_data[1];
	// sendAck = true;
	if (rxNum != ackNum) {
	  rxNum = ackNum;
	  rxBuf.write((const uint8_t*) rf12_data + 2, rf12_len - 2);
	  ++rxPackets;
	}

	// if (sendAck) {
	if (RF12_WANTS_ACK) {
	  uint8_t ackData[sizeof(ackNum)];
	  ackData[1] = ackNum & 0xFF;
	  ackData[0] = (ackNum >> 8) & 0xFF;
	  rf12_sendStart(RF12_ACK_REPLY, ackData, sizeof(ackData));
	}
      }

    }

    if (packetTries > maxRetriesPerPacket && retryDelay.isExpired()) {
      // Enough tries on this portion of data
      txBuf.skip(txBytesPending);
      txBytesPending = 0;
      packetTries = 0;
      ++txNum;
    }

    // Check if data to send.
    // txBytesPending == 0 means no unacknowledged data
    if ((txBytesPending == 0 || retryDelay.isExpired()) &&
	txDelay.isExpired() &&
	txBuf.getSize() && rf12_canSend()) {
      if (packetTries > 1)
	++retries;
      else
	++txPackets;

      ++packetTries;
      uint8_t message[sizeof(txNum) + packetDataLength];
      // First two bytes are the TX packet number, sent in network order
      message[1] = txNum & 0xFF;
      message[0] = (txNum >> 8) & 0xFF;
      txBytesPending = txBuf.peek(message+sizeof(txNum), packetDataLength);
      uint8_t hdr = RF12_HDR_ACK; // RF12_HDR_DST | 0x02;
      rf12_sendStart(hdr, message, sizeof(txNum) + txBytesPending);
      retryDelay.start(retryDelay_ms, AsyncDelay::MILLIS);
    }
  //}
}

int RF12_Stream::available(void)
{
  return rxBuf.getSize();
}

int RF12_Stream::peek(void)
{
  uint8_t c;
  if (rxBuf.peek(&c, sizeof(c)))
    return c;
  else
    return -1;
}

int RF12_Stream::read(void)
{
  uint8_t c;
  if (rxBuf.read(&c, sizeof(c)))
    return c;
  else
    return -1;
}

void RF12_Stream::flush()
{
  // Expire the TX timer and wait for any existing data to be
  // sent. Use timer to prevent lockups.
  txDelay.expire();
  AsyncDelay flushTimeout(flushTimeout_ms, AsyncDelay::MILLIS);
  while (txBytesPending && txBuf.getSize() && !flushTimeout.isExpired())
    poll();
  txBuf.clear();
}

size_t RF12_Stream::write(uint8_t c)
{
  size_t bytesWritten;
  int initialSize = txBuf.getSize();
  bytesWritten = txBuf.write(&c, sizeof(c));
  if (initialSize == 0 && bytesWritten)
    // Start the TX timer when the first character to be sent is received.
    txDelay.start(txDelay_ms, AsyncDelay::MILLIS);
  return bytesWritten;
}

bool RF12_Stream::powerOn(void)
{
  rf12_sleep(RF12_WAKEUP);
  txBuf.clear();
  rxBuf.clear();
  return true;
}

bool RF12_Stream::powerOff(void)
{
  if (txBuf.getSize() && !txDelay.isExpired())
    return false; // Wait for TX buffer to be sent
  rf12_sleep(RF12_SLEEP);
  txBuf.clear();
  rxBuf.clear();
  return true;
}

void RF12_Stream::detectHandler(void)
{
  if (rf12_control(0x0000) & 0x4000)
    isPresent = true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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.

// When used in conjunction with module_embedder.h, this gives a default
// implementation of ppp.h for clients of the ppapi C++ interface.  Most
// plugin implementors can export their derivation of Module by just
// linking to this implementation.

#include "ppapi/c/ppb.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_embedder.h"

static pp::Module* g_module_singleton = NULL;
static PP_GetInterface_Func g_broker_get_interface = NULL;

namespace pp {

// Give a default implementation of Module::Get().  See module.cc for details.
pp::Module* Module::Get() {
  return g_module_singleton;
}

void SetBrokerGetIntefaceFunc(PP_GetInterface_Func broker_get_interface) {
  g_broker_get_interface = broker_get_interface;
}

}  // namespace pp

// Global PPP functions --------------------------------------------------------

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module_id,
                                       PPB_GetInterface get_browser_interface) {
  pp::Module* module = pp::CreateModule();
  if (!module)
    return PP_ERROR_FAILED;

  if (!module->InternalInit(module_id, get_browser_interface)) {
    delete module;
    return PP_ERROR_FAILED;
  }
  g_module_singleton = module;
  return PP_OK;
}

PP_EXPORT void PPP_ShutdownModule() {
  delete g_module_singleton;
  g_module_singleton = NULL;
}

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
  if (g_module_singleton)
    return g_module_singleton->GetPluginInterface(interface_name);
  if (g_broker_get_interface)
    return g_broker_get_interface(interface_name);
  return NULL;
}
<commit_msg>Fix typo.<commit_after>// Copyright (c) 2012 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.

// When used in conjunction with module_embedder.h, this gives a default
// implementation of ppp.h for clients of the ppapi C++ interface.  Most
// plugin implementors can export their derivation of Module by just
// linking to this implementation.

#include "ppapi/c/ppb.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_embedder.h"

static pp::Module* g_module_singleton = NULL;
static PP_GetInterface_Func g_broker_get_interface = NULL;

namespace pp {

// Give a default implementation of Module::Get().  See module.cc for details.
pp::Module* Module::Get() {
  return g_module_singleton;
}

void SetBrokerGetInterfaceFunc(PP_GetInterface_Func broker_get_interface) {
  g_broker_get_interface = broker_get_interface;
}

}  // namespace pp

// Global PPP functions --------------------------------------------------------

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module_id,
                                       PPB_GetInterface get_browser_interface) {
  pp::Module* module = pp::CreateModule();
  if (!module)
    return PP_ERROR_FAILED;

  if (!module->InternalInit(module_id, get_browser_interface)) {
    delete module;
    return PP_ERROR_FAILED;
  }
  g_module_singleton = module;
  return PP_OK;
}

PP_EXPORT void PPP_ShutdownModule() {
  delete g_module_singleton;
  g_module_singleton = NULL;
}

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
  if (g_module_singleton)
    return g_module_singleton->GetPluginInterface(interface_name);
  if (g_broker_get_interface)
    return g_broker_get_interface(interface_name);
  return NULL;
}
<|endoftext|>


<commit_before>// Copyright 2021 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

//===- SPIRVVectorize.cpp -------------------------------------------------===//
//
// This pass vectorizes Linalg ops with buffer semantics.
//
//===----------------------------------------------------------------------===//

#include "iree/compiler/Codegen/PassDetail.h"
#include "iree/compiler/Codegen/Passes.h"
#include "iree/compiler/Codegen/SPIRV/Utils.h"
#include "iree/compiler/Codegen/Transforms/Transforms.h"
#include "iree/compiler/Codegen/Utils/MarkerUtils.h"
#include "iree/compiler/Codegen/Utils/Utils.h"
#include "llvm/Support/Debug.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Transforms/Hoisting.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/Dialect/Vector/VectorTransforms.h"
#include "mlir/Interfaces/VectorInterfaces.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"

#define DEBUG_TYPE "iree-spirv-vectorize"

namespace mlir {
namespace iree_compiler {
namespace {

/// Returns the cooperative matrix (M, N, K) sizes that are supported by the
/// target environment and match the given parameters.
static Optional<SmallVector<int64_t, 4>> getCooperativeMatmulSubgroupSize(
    spirv::ResourceLimitsAttr resourceLimits, Type lhsType, Type rhsType,
    Type initType, Type resultType) {
  auto range = resourceLimits.cooperative_matrix_properties_nv()
                   .getAsRange<spirv::CooperativeMatrixPropertiesNVAttr>();
  for (auto coopMatmulProperties : range) {
    if (coopMatmulProperties.a_type().getValue() == lhsType &&
        coopMatmulProperties.b_type().getValue() == rhsType &&
        coopMatmulProperties.c_type().getValue() == initType &&
        coopMatmulProperties.result_type().getValue() == resultType &&
        coopMatmulProperties.scope().getValue() == spirv::Scope::Subgroup) {
      return SmallVector<int64_t, 4>{
          coopMatmulProperties.m_size().getValue().getSExtValue(),
          coopMatmulProperties.n_size().getValue().getSExtValue(),
          coopMatmulProperties.k_size().getValue().getSExtValue()};
    }
  }
  return llvm::None;
}

/// Returns true if the target environment attached to `op`'s ancestor op
/// supports cooperative matrix.
bool useCooperativeMatrix(Operation *op) {
  auto attr = getSPIRVTargetEnvAttr(op);
  if (!attr) return false;

  auto targetEnv = spirv::TargetEnv(attr);
  return targetEnv.allows(spirv::Capability::CooperativeMatrixNV) &&
         targetEnv.allows(spirv::Extension::SPV_NV_cooperative_matrix);
}

Optional<SmallVector<int64_t, 4>> getSPIRVNativeVectorSize(Operation *op) {
  bool useCoopMatrix = useCooperativeMatrix(op);

  if (OpTrait::hasElementwiseMappableTraits(op) && op->getNumResults() == 1) {
    if (auto vecType = op->getResultTypes()[0].dyn_cast<VectorType>()) {
      // Use 4-element vectors for elementwise ops.
      SmallVector<int64_t, 4> nativeSize(vecType.getRank(), 1);
      nativeSize.back() = 4;
      return nativeSize;
    }
  } else if (auto vtOp = dyn_cast<VectorTransferOpInterface>(op)) {
    if (useCoopMatrix) {
      if (auto writeOp = dyn_cast<vector::TransferWriteOp>(op)) {
        // Unroll cooperative martrix store based on the size of the contract.
        auto insert =
            writeOp.vector().getDefiningOp<vector::InsertStridedSliceOp>();
        if (!insert) return llvm::None;
        ArrayRef<int64_t> shape = insert.getSourceVectorType().getShape();
        return SmallVector<int64_t, 4>(shape.begin(), shape.end());
      } else if (auto readOp = dyn_cast<vector::TransferReadOp>(op)) {
        // Unroll cooperative martrix load based on the size of the contract.
        VectorType dstVec;
        for (Operation *users : op->getUsers()) {
          auto extract = dyn_cast<vector::ExtractStridedSliceOp>(users);
          if (!extract) return llvm::None;
          auto vecType = extract.getResult().getType().cast<VectorType>();
          if (dstVec && dstVec != vecType) return llvm::None;
          dstVec = vecType;
        }
        return SmallVector<int64_t, 4>(dstVec.getShape().begin(),
                                       dstVec.getShape().end());
      }
    } else {
      auto rank = vtOp.getVectorType().getRank();
      SmallVector<int64_t, 4> nativeSize(rank, 1);
      for (auto dim : llvm::enumerate(vtOp.permutation_map().getResults())) {
        if (auto dimExpr = dim.value().dyn_cast<AffineDimExpr>()) {
          if (dimExpr.getPosition() == vtOp.permutation_map().getNumDims() - 1)
            nativeSize[dim.index()] = 4;
        }
      }
      return nativeSize;
    }
  } else if (auto contractOp = dyn_cast<vector::ContractionOp>(op)) {
    if (useCoopMatrix) {
      auto targetEnv = spirv::TargetEnv(getSPIRVTargetEnvAttr(op));
      return getCooperativeMatmulSubgroupSize(
          targetEnv.getResourceLimits(),
          contractOp.getLhsType().getElementType(),
          contractOp.getRhsType().getElementType(),
          contractOp.getAccType().cast<VectorType>().getElementType(),
          contractOp.getResultType().cast<VectorType>().getElementType());
    } else {
      unsigned lastParalleldim = 0;
      for (auto it : llvm::enumerate(contractOp.iterator_types())) {
        if (isParallelIterator(it.value())) lastParalleldim = it.index();
      }
      SmallVector<int64_t, 4> nativeSize(contractOp.iterator_types().size(), 1);
      nativeSize[lastParalleldim] = 4;
      // Map to vec4 fma operations.
      return nativeSize;
    }
  }
  return llvm::None;
}

/// Add patterns to vectorize Linalg ops with vectorization marker.
void populateVectorizationPatterns(MLIRContext *context,
                                   RewritePatternSet &patterns) {
  linalg::insertVectorizationPatterns<linalg::FillOp, linalg::GenericOp,
                                      linalg::ContractionOpInterface>(
      patterns, linalg::LinalgVectorizationOptions(),
      linalg::LinalgTransformationFilter(
          Identifier::get(getVectorizeMarker(), context)));
}

/// Adds patterns to unroll vector ops to SPIR-V native vector size.
void populateVectorUnrollPatterns(MLIRContext *context,
                                  RewritePatternSet &patterns) {
  vector::populateVectorUnrollPatterns(
      patterns,
      vector::UnrollVectorOptions().setNativeShapeFn(getSPIRVNativeVectorSize));
}

/// Workaround SPIR-V backend limitations. SPIR-V vetorization pass relies on
/// unrolling to reduce instructions to a vector size we can convert to SPIR-V.
/// When vectorization creates transpose those block unrolling and result in
/// large vector we currently cannot lower. For now we always merge the
/// transpose into the contract op so that it can be unrolled.
// TODO(thomasraoux): Make transpose work with the current unrolling mechanism
// or replace unrolling.
class CombineContractTranspose final
    : public OpRewritePattern<vector::ContractionOp> {
 public:
  using OpRewritePattern<vector::ContractionOp>::OpRewritePattern;

  LogicalResult matchAndRewrite(vector::ContractionOp op,
                                PatternRewriter &rewriter) const override {
    // Perform lhs + rhs transpositions to conform to matmul row-major
    // semantics. Bail out if the contraction cannot be put in this form.
    MLIRContext *ctx = op.getContext();
    Location loc = op.getLoc();
    bool foundTranspose = false;
    std::array<Value, 3> sources = {op.lhs(), op.rhs(), op.acc()};
    SmallVector<AffineMap> newMaps;
    SmallVector<Value> newSources;
    for (auto source : llvm::enumerate(sources)) {
      auto map =
          op.indexing_maps()[source.index()].cast<AffineMapAttr>().getValue();
      auto tranposeOp = source.value().getDefiningOp<vector::TransposeOp>();
      if (!tranposeOp) {
        newSources.push_back(source.value());
        newMaps.push_back(map);
        continue;
      }
      SmallVector<int64_t, 3> perm;
      tranposeOp.getTransp(perm);
      SmallVector<AffineExpr> exprs(perm.size());
      for (auto remap : llvm::enumerate(perm)) {
        exprs[remap.value()] = map.getResult(remap.index());
      }
      newMaps.push_back(
          AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs, ctx));
      newSources.push_back(tranposeOp.vector());
      foundTranspose = true;
    }
    if (!foundTranspose) return failure();

    Value res = rewriter.create<vector::ContractionOp>(
        loc, newSources[0], newSources[1], newSources[2],
        rewriter.getAffineMapArrayAttr(newMaps), op.iterator_types());
    rewriter.replaceOp(op, res);
    return success();
  }
};

/// Vectorizes Linalg ops on buffer semantics.
class SPIRVVectorizePass : public SPIRVVectorizeBase<SPIRVVectorizePass> {
 public:
  SPIRVVectorizePass() = default;
  SPIRVVectorizePass(const SPIRVVectorizePass &pass) = default;

  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<linalg::LinalgDialect, vector::VectorDialect>();
  }

  void runOnOperation() override {
    MLIRContext *context = &getContext();
    FuncOp funcOp = getOperation();

    auto entryPointOp = getEntryPoint(funcOp);
    if (!entryPointOp) return;

    {
      RewritePatternSet vectorizationPatterns(&getContext());
      populateVectorizationPatterns(context, vectorizationPatterns);
      populateLinalgToVectorVectorizeConvPatterns(context,
                                                  vectorizationPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(vectorizationPatterns));

      LLVM_DEBUG({
        llvm::dbgs() << "--- After vectorization ---\n";
        funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
        llvm::dbgs() << "\n\n";
      });
    }

    // TODO: This should be a folding of Add into Contract in core but while
    // they live in different dialects, it is not possible without unnatural
    // dependencies.
    funcOp.walk([&](Operation *op) {
      if (auto contract = canonicalizeContractionAdd(op))
        op->replaceAllUsesWith(contract);
    });

    {
      RewritePatternSet vectorUnrollPatterns(funcOp.getContext());
      populateVectorUnrollPatterns(funcOp.getContext(), vectorUnrollPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(vectorUnrollPatterns));
    }

    {
      linalg::hoistRedundantVectorTransfers(funcOp);

      LLVM_DEBUG({
        llvm::dbgs() << "--- After hoisting vector transfers ---\n";
        funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
        llvm::dbgs() << "\n\n";
      });
    }

    {
      RewritePatternSet canonicalizationPatterns(funcOp.getContext());
      vector::populateVectorTransferPermutationMapLoweringPatterns(
          canonicalizationPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(canonicalizationPatterns));

      if (useCooperativeMatrix(funcOp)) {
        // When using cooperative matrix we don't want to lower the contract,
        // instead we want to merge contract and transpose so that they can be
        // converted to cooperative matrix matmul op.
        // TODO(thomasraoux): remove that once we support cooperative matrix
        // lowering in MLIR core.
        RewritePatternSet combineTransposePatterns(funcOp.getContext());
        combineTransposePatterns.add<CombineContractTranspose>(
            funcOp.getContext());
        (void)applyPatternsAndFoldGreedily(funcOp,
                                           std::move(combineTransposePatterns));
      } else {
        RewritePatternSet contractLoweringPatterns(funcOp.getContext());
        vector::populateVectorContractLoweringPatterns(
            contractLoweringPatterns,
            vector::VectorTransformsOptions().setVectorTransformsOptions(
                vector::VectorContractLowering::OuterProduct));
        (void)applyPatternsAndFoldGreedily(funcOp,
                                           std::move(contractLoweringPatterns));
      }
    }

    LLVM_DEBUG({
      llvm::dbgs() << "--- After unrolling vector ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createSPIRVVectorizePass() {
  return std::make_unique<SPIRVVectorizePass>();
}

}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>[spirv] NFC: Tidy up SPIRVVectorizePass debug print logic (#7239)<commit_after>// Copyright 2021 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

//===- SPIRVVectorize.cpp -------------------------------------------------===//
//
// This pass vectorizes Linalg ops with buffer semantics.
//
//===----------------------------------------------------------------------===//

#include "iree/compiler/Codegen/PassDetail.h"
#include "iree/compiler/Codegen/Passes.h"
#include "iree/compiler/Codegen/SPIRV/Utils.h"
#include "iree/compiler/Codegen/Transforms/Transforms.h"
#include "iree/compiler/Codegen/Utils/MarkerUtils.h"
#include "iree/compiler/Codegen/Utils/Utils.h"
#include "llvm/Support/Debug.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Transforms/Hoisting.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/Dialect/Vector/VectorTransforms.h"
#include "mlir/Interfaces/VectorInterfaces.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"

#define DEBUG_TYPE "iree-spirv-vectorize"

namespace mlir {
namespace iree_compiler {
namespace {

/// Returns the cooperative matrix (M, N, K) sizes that are supported by the
/// target environment and match the given parameters.
static Optional<SmallVector<int64_t, 4>> getCooperativeMatmulSubgroupSize(
    spirv::ResourceLimitsAttr resourceLimits, Type lhsType, Type rhsType,
    Type initType, Type resultType) {
  auto range = resourceLimits.cooperative_matrix_properties_nv()
                   .getAsRange<spirv::CooperativeMatrixPropertiesNVAttr>();
  for (auto coopMatmulProperties : range) {
    if (coopMatmulProperties.a_type().getValue() == lhsType &&
        coopMatmulProperties.b_type().getValue() == rhsType &&
        coopMatmulProperties.c_type().getValue() == initType &&
        coopMatmulProperties.result_type().getValue() == resultType &&
        coopMatmulProperties.scope().getValue() == spirv::Scope::Subgroup) {
      return SmallVector<int64_t, 4>{
          coopMatmulProperties.m_size().getValue().getSExtValue(),
          coopMatmulProperties.n_size().getValue().getSExtValue(),
          coopMatmulProperties.k_size().getValue().getSExtValue()};
    }
  }
  return llvm::None;
}

/// Returns true if the target environment attached to `op`'s ancestor op
/// supports cooperative matrix.
bool useCooperativeMatrix(Operation *op) {
  auto attr = getSPIRVTargetEnvAttr(op);
  if (!attr) return false;

  auto targetEnv = spirv::TargetEnv(attr);
  return targetEnv.allows(spirv::Capability::CooperativeMatrixNV) &&
         targetEnv.allows(spirv::Extension::SPV_NV_cooperative_matrix);
}

Optional<SmallVector<int64_t, 4>> getSPIRVNativeVectorSize(Operation *op) {
  bool useCoopMatrix = useCooperativeMatrix(op);

  if (OpTrait::hasElementwiseMappableTraits(op) && op->getNumResults() == 1) {
    if (auto vecType = op->getResultTypes()[0].dyn_cast<VectorType>()) {
      // Use 4-element vectors for elementwise ops.
      SmallVector<int64_t, 4> nativeSize(vecType.getRank(), 1);
      nativeSize.back() = 4;
      return nativeSize;
    }
  } else if (auto vtOp = dyn_cast<VectorTransferOpInterface>(op)) {
    if (useCoopMatrix) {
      if (auto writeOp = dyn_cast<vector::TransferWriteOp>(op)) {
        // Unroll cooperative martrix store based on the size of the contract.
        auto insert =
            writeOp.vector().getDefiningOp<vector::InsertStridedSliceOp>();
        if (!insert) return llvm::None;
        ArrayRef<int64_t> shape = insert.getSourceVectorType().getShape();
        return SmallVector<int64_t, 4>(shape.begin(), shape.end());
      } else if (auto readOp = dyn_cast<vector::TransferReadOp>(op)) {
        // Unroll cooperative martrix load based on the size of the contract.
        VectorType dstVec;
        for (Operation *users : op->getUsers()) {
          auto extract = dyn_cast<vector::ExtractStridedSliceOp>(users);
          if (!extract) return llvm::None;
          auto vecType = extract.getResult().getType().cast<VectorType>();
          if (dstVec && dstVec != vecType) return llvm::None;
          dstVec = vecType;
        }
        return SmallVector<int64_t, 4>(dstVec.getShape().begin(),
                                       dstVec.getShape().end());
      }
    } else {
      auto rank = vtOp.getVectorType().getRank();
      SmallVector<int64_t, 4> nativeSize(rank, 1);
      for (auto dim : llvm::enumerate(vtOp.permutation_map().getResults())) {
        if (auto dimExpr = dim.value().dyn_cast<AffineDimExpr>()) {
          if (dimExpr.getPosition() == vtOp.permutation_map().getNumDims() - 1)
            nativeSize[dim.index()] = 4;
        }
      }
      return nativeSize;
    }
  } else if (auto contractOp = dyn_cast<vector::ContractionOp>(op)) {
    if (useCoopMatrix) {
      auto targetEnv = spirv::TargetEnv(getSPIRVTargetEnvAttr(op));
      return getCooperativeMatmulSubgroupSize(
          targetEnv.getResourceLimits(),
          contractOp.getLhsType().getElementType(),
          contractOp.getRhsType().getElementType(),
          contractOp.getAccType().cast<VectorType>().getElementType(),
          contractOp.getResultType().cast<VectorType>().getElementType());
    } else {
      unsigned lastParalleldim = 0;
      for (auto it : llvm::enumerate(contractOp.iterator_types())) {
        if (isParallelIterator(it.value())) lastParalleldim = it.index();
      }
      SmallVector<int64_t, 4> nativeSize(contractOp.iterator_types().size(), 1);
      nativeSize[lastParalleldim] = 4;
      // Map to vec4 fma operations.
      return nativeSize;
    }
  }
  return llvm::None;
}

/// Add patterns to vectorize Linalg ops with vectorization marker.
void populateVectorizationPatterns(MLIRContext *context,
                                   RewritePatternSet &patterns) {
  linalg::insertVectorizationPatterns<linalg::FillOp, linalg::GenericOp,
                                      linalg::ContractionOpInterface>(
      patterns, linalg::LinalgVectorizationOptions(),
      linalg::LinalgTransformationFilter(
          Identifier::get(getVectorizeMarker(), context)));
}

/// Adds patterns to unroll vector ops to SPIR-V native vector size.
void populateVectorUnrollPatterns(MLIRContext *context,
                                  RewritePatternSet &patterns) {
  vector::populateVectorUnrollPatterns(
      patterns,
      vector::UnrollVectorOptions().setNativeShapeFn(getSPIRVNativeVectorSize));
}

/// Workaround SPIR-V backend limitations. SPIR-V vetorization pass relies on
/// unrolling to reduce instructions to a vector size we can convert to SPIR-V.
/// When vectorization creates transpose those block unrolling and result in
/// large vector we currently cannot lower. For now we always merge the
/// transpose into the contract op so that it can be unrolled.
// TODO(thomasraoux): Make transpose work with the current unrolling mechanism
// or replace unrolling.
class CombineContractTranspose final
    : public OpRewritePattern<vector::ContractionOp> {
 public:
  using OpRewritePattern<vector::ContractionOp>::OpRewritePattern;

  LogicalResult matchAndRewrite(vector::ContractionOp op,
                                PatternRewriter &rewriter) const override {
    // Perform lhs + rhs transpositions to conform to matmul row-major
    // semantics. Bail out if the contraction cannot be put in this form.
    MLIRContext *ctx = op.getContext();
    Location loc = op.getLoc();
    bool foundTranspose = false;
    std::array<Value, 3> sources = {op.lhs(), op.rhs(), op.acc()};
    SmallVector<AffineMap> newMaps;
    SmallVector<Value> newSources;
    for (auto source : llvm::enumerate(sources)) {
      auto map =
          op.indexing_maps()[source.index()].cast<AffineMapAttr>().getValue();
      auto tranposeOp = source.value().getDefiningOp<vector::TransposeOp>();
      if (!tranposeOp) {
        newSources.push_back(source.value());
        newMaps.push_back(map);
        continue;
      }
      SmallVector<int64_t, 3> perm;
      tranposeOp.getTransp(perm);
      SmallVector<AffineExpr> exprs(perm.size());
      for (auto remap : llvm::enumerate(perm)) {
        exprs[remap.value()] = map.getResult(remap.index());
      }
      newMaps.push_back(
          AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs, ctx));
      newSources.push_back(tranposeOp.vector());
      foundTranspose = true;
    }
    if (!foundTranspose) return failure();

    Value res = rewriter.create<vector::ContractionOp>(
        loc, newSources[0], newSources[1], newSources[2],
        rewriter.getAffineMapArrayAttr(newMaps), op.iterator_types());
    rewriter.replaceOp(op, res);
    return success();
  }
};

/// Vectorizes Linalg ops on buffer semantics.
class SPIRVVectorizePass : public SPIRVVectorizeBase<SPIRVVectorizePass> {
 public:
  SPIRVVectorizePass() = default;
  SPIRVVectorizePass(const SPIRVVectorizePass &pass) = default;

  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<linalg::LinalgDialect, vector::VectorDialect>();
  }

  void runOnOperation() override {
    MLIRContext *context = &getContext();
    FuncOp funcOp = getOperation();

    auto entryPointOp = getEntryPoint(funcOp);
    if (!entryPointOp) return;

    {
      RewritePatternSet vectorizationPatterns(&getContext());
      populateVectorizationPatterns(context, vectorizationPatterns);
      populateLinalgToVectorVectorizeConvPatterns(context,
                                                  vectorizationPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(vectorizationPatterns));
    }

    LLVM_DEBUG({
      llvm::dbgs() << "--- After vectorization ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });

    // TODO: This should be a folding of Add into Contract in core but while
    // they live in different dialects, it is not possible without unnatural
    // dependencies.
    funcOp.walk([&](Operation *op) {
      if (auto contract = canonicalizeContractionAdd(op))
        op->replaceAllUsesWith(contract);
    });

    {
      RewritePatternSet vectorUnrollPatterns(funcOp.getContext());
      populateVectorUnrollPatterns(funcOp.getContext(), vectorUnrollPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(vectorUnrollPatterns));
    }

    LLVM_DEBUG({
      llvm::dbgs() << "--- After unrolling vector ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });

    linalg::hoistRedundantVectorTransfers(funcOp);

    LLVM_DEBUG({
      llvm::dbgs() << "--- After hoisting vector transfers ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });

    {
      RewritePatternSet canonicalizationPatterns(funcOp.getContext());
      vector::populateVectorTransferPermutationMapLoweringPatterns(
          canonicalizationPatterns);
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(canonicalizationPatterns));
    }

    LLVM_DEBUG({
      llvm::dbgs() << "--- After canonicalizing vectors ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });

    if (useCooperativeMatrix(funcOp)) {
      // When using cooperative matrix we don't want to lower the contract,
      // instead we want to merge contract and transpose so that they can be
      // converted to cooperative matrix matmul op.
      // TODO(thomasraoux): remove that once we support cooperative matrix
      // lowering in MLIR core.
      RewritePatternSet combineTransposePatterns(funcOp.getContext());
      combineTransposePatterns.add<CombineContractTranspose>(
          funcOp.getContext());
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(combineTransposePatterns));
    } else {
      RewritePatternSet contractLoweringPatterns(funcOp.getContext());
      vector::populateVectorContractLoweringPatterns(
          contractLoweringPatterns,
          vector::VectorTransformsOptions().setVectorTransformsOptions(
              vector::VectorContractLowering::OuterProduct));
      (void)applyPatternsAndFoldGreedily(funcOp,
                                         std::move(contractLoweringPatterns));
    }

    LLVM_DEBUG({
      llvm::dbgs() << "--- After handling contraction ---\n";
      funcOp.print(llvm::dbgs(), OpPrintingFlags().useLocalScope());
      llvm::dbgs() << "\n\n";
    });
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createSPIRVVectorizePass() {
  return std::make_unique<SPIRVVectorizePass>();
}

}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


<commit_before>#ifndef SIG_UTIL_SET_HPP
#define SIG_UTIL_SET_HPP

#include "sigutil.hpp"
#include "tool.hpp"

namespace sig
{

#if SIG_ENABLE_BOOST

	//条件に最適な値とそのIndexを探す.　comp(比較対象値, 暫定最小値)
	template < class T, class CMP, template < class T, class = std::allocator<T>> class Container >
	maybe<std::tuple<T, uint>> SearchIndex(Container<T> const& src, CMP comp)
	{
		if (src.empty()) return nothing;

		T val = src[0];
		uint index = 0;

		for (uint i = 0, size = src.size(); i < size; ++i){
			if (comp(src[i], val)){
				val = src[i];
				index = i;
			}
		}

		return std::make_tuple(val, index);
	}

#endif

	inline void Print(std::string const& text, char const* const delimiter = "\n")
	{
		std::cout << text << delimiter;
	}

	inline void Print(std::wstring const& text, wchar_t const* const delimiter = L"\n")
	{
		std::wcout << text << delimiter;
	}

	template < class T, template <class...> class Container, typename std::enable_if<!std::is_same<T, std::wstring>::value>::type*& = enabler>
	inline void Print(Container<T> const& container, char const* const delimiter = "\n")
	{
		std::copy(container.begin(), container.end(), std::ostream_iterator<T>(std::cout, delimiter));
	}

	template<template<class...> class Container>
	inline void Print(Container<std::wstring> const& container, wchar_t const* const delimiter = L"\n")
	{
		std::copy(container.begin(), container.end(), std::ostream_iterator<std::wstring>(std::wcout, delimiter));
	}
}

#endif<commit_msg>add: GaleShapley<commit_after>#ifndef SIG_UTIL_SET_HPP
#define SIG_UTIL_SET_HPP

#include "sigutil.hpp"
#include "tool.hpp"

namespace sig
{

#if SIG_ENABLE_BOOST

	//条件に最適な値とそのIndexを探す.　comp(比較対象値, 暫定最小値)
	template < class T, class CMP, template < class T, class = std::allocator<T>> class Container >
	maybe<std::tuple<T, uint>> SearchIndex(Container<T> const& src, CMP comp)
	{
		if (src.empty()) return nothing;

		T val = src[0];
		uint index = 0;

		for (uint i = 0, size = src.size(); i < size; ++i){
			if (comp(src[i], val)){
				val = src[i];
				index = i;
			}
		}

		return std::make_tuple(val, index);
	}

#endif

	inline void Print(std::string const& text, char const* const delimiter = "\n")
	{
		std::cout << text << delimiter;
	}

	inline void Print(std::wstring const& text, wchar_t const* const delimiter = L"\n")
	{
		std::wcout << text << delimiter;
	}

	template < class T, template <class...> class Container, typename std::enable_if<!std::is_same<T, std::wstring>::value>::type*& = enabler>
	inline void Print(Container<T> const& container, char const* const delimiter = "\n")
	{
		std::copy(container.begin(), container.end(), std::ostream_iterator<T>(std::cout, delimiter));
	}

	template<template<class...> class Container>
	inline void Print(Container<std::wstring> const& container, wchar_t const* const delimiter = L"\n")
	{
		std::copy(container.begin(), container.end(), std::ostream_iterator<std::wstring>(std::wcout, delimiter));
	}

template <class CC1, class CC2>
auto GaleShapley(CC1 const& men_vec, CC2 const& women_vec)
{
	assert(men_vec.size() != women_vec.size());

	uint total = men_vec.size();
	std::vector<uint> keeping(total, total+1);	// 女性が 何位の男性と婚約しているか（初期値N+1）
	std::vector<std::tuple<bool, uint>> single_men(total, std::make_tuple(true, 0));	// 男性が tuple<独身であるか, 告白回数（希望相手女性の順位）>
	std::queue<uint> rest;	// 告発実行待ちの男性のキュー

	// 男性が女性に告白する。戻り値：婚約成功の可否
	auto propose = [&](const uint man, const uint woman) ->bool{
		if(keeping[woman] > total){
			// womanがまだ婚約していない場合
			keeping[woman] = man;
			std::get<0>(single_men[man]) = true;
			return true;
		}
		else{
			for(uint i=0; i<total; ++i){
				if(man == women_vec[woman][i]){
					if(i < keeping[woman]){
						// manがwomanの婚約相手よりも好感度が高い場合
						uint now_man = women_vec[woman][keeping[woman]];
						keeping[woman] = i;
						std::get<0>(single_men[man]) = true;
						// 現婚約者の婚約解消
						std::get<0>(single_men[now_man]) = false;
						rest.push(now_man);
						return true;
					}
					else{
						return false;
					}
				}
			}
		}
	};

	for(uint i=0; i<total; ++i) rest.push(i);

	while (!rest.empty()){
		const uint man = rest.front();
		const uint propose_woman = men_vec[man][std::get<1>(single_men[man])];
		++std::get<1>(single_men[man]);
		if (propose(man, propose_woman)) rest.pop();
	}
}
}

#endif<|endoftext|>


<commit_before>#include "Tools.hpp"
#include "include/XID_map.hpp"
#include "include/XyDelta_FileInterface.hpp"
#include "include/XyLatinStr.hpp"
#include "DeltaException.hpp"

#include "xercesc/util/PlatformUtils.hpp"
#include "xercesc/dom/DOMException.hpp"

#include <stdio.h>
#include <math.h>
#include <fstream>

#include <sys/timeb.h>

#define HWPROF_LOG 0

#if HWPROF_LOG
FILE *timeFile ;

extern unsigned long long int   clocksCDDsaveXidMap        ;
extern unsigned long long int clocksRegisterSubtree        ;
extern unsigned long long int clocksTopDownMatch           ;
extern unsigned long long int clocksOptimize               ;
extern unsigned long long int clocksConstructDeltaDocument ;
extern unsigned long long int clocksSaveDelta              ;

#endif

XERCES_CPP_NAMESPACE_USE

unsigned long getFileSize(const char *filename) {
        FILE *file = fopen(filename, "rb");
        if (file==NULL) return(0);

        (void)fseek(file, 0, SEEK_END);
        unsigned long size = ftell( file );
        fclose(file);
        return size ;
        }

int main(int argc, char **argv) {

#if HWPROF_LOG
	timeFile = fopen("timefile.txt", "wb");
	if (timeFile==NULL) {
 		fprintf(stderr, "could not open timefile.txt\n");
		exit(0);
		}
	printf("Logging time profile\n");
#endif

	std::string file1, file2 ;
	bool ignoreSpacesFlag=false;
	bool defaultDeltafile=true;
	bool verbose=false;
	std::string deltafile ;

	bool help=false;
	for(int i=1; i<argc; i++) if (strcmp(argv[i], "--help")==0) help=true;

	int pos=0;
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "-v")==0)) {
		verbose=true;
		pos++;
		}
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "--ignore-spaces")==0)) {
		ignoreSpacesFlag=true;
		pos++;
		}
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "-o")==0)) {
		if (argc<pos+3) help=true;
		else deltafile=argv[pos+2];
		pos+=2;
		defaultDeltafile=false;
		}
	if (argc<pos+3) help=true;
	if (!help) {
		file1=argv[pos+1];
		file2=argv[pos+2];
		pos+=2;
		if (argc>pos+1) help=true;
		}

	if (help) {
		std::cerr << "usage       : exec [-v] [--ignore-spaces] [-o deltafile.xml] file1.xml file2.xml" << std::endl ;
		std::cerr << "example     : exec -o ex_delta.xml example1.xml example1bis.xml" << std::endl ;
		std::cerr << "description : " << std::endl ;
		std::cerr << "              file1.xml, file2.xml : XyDiff creates a delta representing changes\n"
		     << "                                     that transform <file1.xml> into <file2.xml>" << std::endl;
		std::cerr << "              -v                   : verbose\n" << std::endl ;
		std::cerr << "              --ignore-spaces      : ignore some differences between documents\n"
		     << "                                     if they only concern blank text parts\n"
				 << "                                     (e.g. white spaces used for indentation)" << std::endl;
		std::cerr << "              -o deltafile.xml     : file to store the delta.\n"
		     << "                                     by default <file1.xml.forwardDelta.xml>" << std::endl ;
		exit(-2);
		}

	try {
    XMLPlatformUtils::Initialize();
    }
  catch(const XMLException& toCatch) {
    std::cerr << "Error during Xerces-c Initialization.\n" << "  Exception message:" << XyLatinStr(toCatch.getMessage()).localForm() << std::endl;
    }

  // Open source document, and create DELTA

	try {
		// if (defaultDeltafile) deltafile=file1+".forwardDelta.xml";
		if (defaultDeltafile) deltafile="stdout";
		/* Compute Delta over FILE1.XML and FILE2.XML */
		XyDelta::XyDiff(file1.c_str(), file2.c_str(), deltafile.c_str(), ignoreSpacesFlag);

#if HWPROF_LOG
		if (timeFile!=NULL) {
			printf("add timing profile to log\n");
			// Time Data for Algorithm Analysis
			unsigned long long int phase2 = clocksRegisterSubtree ;
			unsigned long long int phase3 = clocksTopDownMatch ;
			unsigned long long int phase4 = clocksOptimize ;
			unsigned long long int phase5 = clocksConstructDeltaDocument - clocksCDDsaveXidMap ;
			fprintf(timeFile, "# data size, phase1+2; phase3; phase4; phase5\n");
			unsigned long dataSize = getFileSize(v0filename)+getFileSize(v1filename) ;
			fprintf(timeFile, "%7d %7d %7d %7d %7d\n",
								(int)dataSize,
						    (int)(phase2/(CLOCKRATE/1000000)),
								(int)(phase3/(CLOCKRATE/1000000)),
								(int)(phase4/(CLOCKRATE/1000000)),
								(int)(phase5/(CLOCKRATE/1000000))
								);
			}
#endif
		}

	catch( const DeltaException &e ) {
		std::cerr << "delta exception. Exit program" << std::endl ;
		exit(-1);
		}

	catch( const VersionManagerException &e ) {
		std::cerr << e << std::endl ;
		exit(-1);
		}

	catch( const DOMException &e ) {
		std::cerr << "DOMException, code=" << e.code << std::endl ;
		char * tmpChar = XMLString::transcode(e.msg);
		std::cerr << "DOMException, message=" << tmpChar << std::endl ;
		XMLString::release(&tmpChar);
		exit(-1);
		}

#if HWPROF_LOG
	fclose( timeFile );
#endif

	return(0);
	}

<commit_msg>Whitespace cleanup<commit_after>#include "Tools.hpp"
#include "include/XID_map.hpp"
#include "include/XyDelta_FileInterface.hpp"
#include "include/XyLatinStr.hpp"
#include "DeltaException.hpp"

#include "xercesc/util/PlatformUtils.hpp"
#include "xercesc/dom/DOMException.hpp"

#include <stdio.h>
#include <math.h>
#include <fstream>

#include <sys/timeb.h>

#define HWPROF_LOG 0

#if HWPROF_LOG
FILE *timeFile ;

extern unsigned long long int   clocksCDDsaveXidMap        ;
extern unsigned long long int clocksRegisterSubtree        ;
extern unsigned long long int clocksTopDownMatch           ;
extern unsigned long long int clocksOptimize               ;
extern unsigned long long int clocksConstructDeltaDocument ;
extern unsigned long long int clocksSaveDelta              ;

#endif

XERCES_CPP_NAMESPACE_USE

unsigned long getFileSize(const char *filename) {
        FILE *file = fopen(filename, "rb");
        if (file==NULL) return(0);

        (void)fseek(file, 0, SEEK_END);
        unsigned long size = ftell( file );
        fclose(file);
        return size ;
        }

int main(int argc, char **argv) {

#if HWPROF_LOG
	timeFile = fopen("timefile.txt", "wb");
	if (timeFile==NULL) {
 		fprintf(stderr, "could not open timefile.txt\n");
		exit(0);
		}
	printf("Logging time profile\n");
#endif

	std::string file1, file2 ;
	bool ignoreSpacesFlag=false;
	bool defaultDeltafile=true;
	bool verbose=false;
	std::string deltafile ;

	bool help=false;
	for(int i=1; i<argc; i++) if (strcmp(argv[i], "--help")==0) help=true;

	int pos=0;
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "-v")==0)) {
		verbose=true;
		pos++;
		}
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "--ignore-spaces")==0)) {
		ignoreSpacesFlag=true;
		pos++;
		}
	if (argc<pos+2) help=true;
	if ((!help)&&(strcmp(argv[pos+1], "-o")==0)) {
		if (argc<pos+3) help=true;
		else deltafile=argv[pos+2];
		pos+=2;
		defaultDeltafile=false;
		}
	if (argc<pos+3) help=true;
	if (!help) {
		file1=argv[pos+1];
		file2=argv[pos+2];
		pos+=2;
		if (argc>pos+1) help=true;
		}

	if (help) {
		std::cerr << "usage       : exec [-v] [--ignore-spaces] [-o deltafile.xml] file1.xml file2.xml" << std::endl ;
		std::cerr << "example     : exec -o ex_delta.xml example1.xml example1bis.xml" << std::endl ;
		std::cerr << "description : " << std::endl ;
		std::cerr << "              file1.xml, file2.xml : XyDiff creates a delta representing changes\n"
		          << "                                     that transform <file1.xml> into <file2.xml>" << std::endl;
		std::cerr << "              -v                   : verbose\n" << std::endl ;
		std::cerr << "              --ignore-spaces      : ignore some differences between documents\n"
				  << "                                     if they only concern blank text parts\n"
				  << "                                     (e.g. white spaces used for indentation)" << std::endl;
		std::cerr << "              -o deltafile.xml     : file to store the delta.\n"
				  << "                                     by default <file1.xml.forwardDelta.xml>" << std::endl ;
		exit(-2);
		}

	try {
		XMLPlatformUtils::Initialize();
	}
	catch(const XMLException& toCatch) {
		std::cerr << "Error during Xerces-c Initialization.\n" << "  Exception message:" << XyLatinStr(toCatch.getMessage()).localForm() << std::endl;
	}

  // Open source document, and create DELTA

	try {
		// if (defaultDeltafile) deltafile=file1+".forwardDelta.xml";
		if (defaultDeltafile) deltafile="stdout";
		/* Compute Delta over FILE1.XML and FILE2.XML */
		XyDelta::XyDiff(file1.c_str(), file2.c_str(), deltafile.c_str(), ignoreSpacesFlag);

#if HWPROF_LOG
		if (timeFile!=NULL) {
			printf("add timing profile to log\n");
			// Time Data for Algorithm Analysis
			unsigned long long int phase2 = clocksRegisterSubtree ;
			unsigned long long int phase3 = clocksTopDownMatch ;
			unsigned long long int phase4 = clocksOptimize ;
			unsigned long long int phase5 = clocksConstructDeltaDocument - clocksCDDsaveXidMap ;
			fprintf(timeFile, "# data size, phase1+2; phase3; phase4; phase5\n");
			unsigned long dataSize = getFileSize(v0filename)+getFileSize(v1filename) ;
			fprintf(timeFile, "%7d %7d %7d %7d %7d\n",
								(int)dataSize,
								(int)(phase2/(CLOCKRATE/1000000)),
								(int)(phase3/(CLOCKRATE/1000000)),
								(int)(phase4/(CLOCKRATE/1000000)),
								(int)(phase5/(CLOCKRATE/1000000))
								);
			}
#endif
		}

	catch( const DeltaException &e ) {
		std::cerr << "delta exception. Exit program" << std::endl ;
		exit(-1);
		}

	catch( const VersionManagerException &e ) {
		std::cerr << e << std::endl ;
		exit(-1);
		}

	catch( const DOMException &e ) {
		std::cerr << "DOMException, code=" << e.code << std::endl ;
		char * tmpChar = XMLString::transcode(e.msg);
		std::cerr << "DOMException, message=" << tmpChar << std::endl ;
		XMLString::release(&tmpChar);
		exit(-1);
		}

#if HWPROF_LOG
	fclose( timeFile );
#endif

	return(0);
	}

<|endoftext|>


<commit_before>/*
 * addrtInst()
 *	Function: Introduce a new rt creation func/object to CMIX
 *	Args:	rt_item structure
 *	Calls:	nothing
 *	Return:	0 on success, -1 on failure
 *  -------> BGG: add these and "mixerr.h" later
 *		MX_FEXIST - ugen by that name already exists
 *		MX_EMEM	  - No memory to create ug_item
 *	Side Effects:
 */
#include "../rtstuff/Instrument.h"
#include "../rtstuff/rt.h"
#include "mixerr.h"
#include <string.h>

extern rt_item *rt_list;

addrtInst(rt_item *rt_p)
{
	rt_item *rt_tail;
	rt_item *rt_temp;

	// printf("ENTERING addrtInst() FUNCTION -----\n");
	/*  Seek end of rt_list	*/
	rt_tail = rt_list;

	if (!rt_tail) { // first one on the list
	  rt_list = rt_p;
	  rt_p->rt_next = NULL;
	  // printf("EXITING addrtInst() FUNCTION (0)-----\n");
	  return 0;
	}
	for (rt_tail=rt_list; rt_tail->rt_next; rt_tail=rt_tail->rt_next)
	{
		if (!strcmp((char *)rt_tail,rt_p->rt_name))	{
			mixerr = MX_FEXIST;
			// printf("EXITING addrtInst() FUNCTION (MX_FEXIST)-----\n");
			return (-1);
		}
	}
	rt_tail->rt_next = rt_p;
	rt_p->rt_next = NULL;
	// printf("EXITING addrtInst() FUNCTION (0)-----\n");
	return (0);
}

<commit_msg>Add copyright notice. Include globals.h.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/

/*
 * addrtInst()
 *	Function: Introduce a new rt creation func/object to CMIX
 *	Args:	rt_item structure
 *	Calls:	nothing
 *	Return:	0 on success, -1 on failure
 *  -------> BGG: add these and "mixerr.h" later
 *		MX_FEXIST - ugen by that name already exists
 *		MX_EMEM	  - No memory to create ug_item
 *	Side Effects:
 */
#include <globals.h>
#include "../rtstuff/rt.h"
#include "../rtstuff/Instrument.h"
#include "mixerr.h"
#include <string.h>

addrtInst(rt_item *rt_p)
{
	rt_item *rt_tail;
	rt_item *rt_temp;

	// printf("ENTERING addrtInst() FUNCTION -----\n");
	/*  Seek end of rt_list	*/
	rt_tail = rt_list;

	if (!rt_tail) { // first one on the list
	  rt_list = rt_p;
	  rt_p->rt_next = NULL;
	  // printf("EXITING addrtInst() FUNCTION (0)-----\n");
	  return 0;
	}
	for (rt_tail=rt_list; rt_tail->rt_next; rt_tail=rt_tail->rt_next)
	{
		if (!strcmp((char *)rt_tail,rt_p->rt_name))	{
			mixerr = MX_FEXIST;
			// printf("EXITING addrtInst() FUNCTION (MX_FEXIST)-----\n");
			return (-1);
		}
	}
	rt_tail->rt_next = rt_p;
	rt_p->rt_next = NULL;
	// printf("EXITING addrtInst() FUNCTION (0)-----\n");
	return (0);
}

<|endoftext|>