<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin-server.
 *
 * libbitcoin-server 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 <bitcoin/server/interface/blockchain.hpp>

#include <cstdint>
#include <cstddef>
#include <functional>
#include <bitcoin/blockchain.hpp>
#include <bitcoin/server/define.hpp>
#include <bitcoin/server/messages/message.hpp>
#include <bitcoin/server/server_node.hpp>
#include <bitcoin/server/utility/fetch_helpers.hpp>

namespace libbitcoin {
namespace server {

using namespace std::placeholders;
using namespace bc::blockchain;
using namespace bc::chain;
using namespace bc::wallet;

void blockchain::fetch_history(server_node& node, const message& request,
    send_handler handler)
{
    static constexpr uint64_t limit = 0;
    uint32_t from_height;
    payment_address address;

    if (!unwrap_fetch_history_args(address, from_height, request))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    log::debug(LOG_SERVER)
        << "blockchain.fetch_history(" << address.encoded()
        << ", from_height=" << from_height << ")";

    node.chain().fetch_history(address, limit, from_height,
        std::bind(send_history_result,
            _1, _2, request, handler));
}

void blockchain::fetch_transaction(server_node& node, const message& request,
    send_handler handler)
{
    hash_digest tx_hash;

    if (!unwrap_fetch_transaction_args(tx_hash, request))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    log::debug(LOG_SERVER)
        << "blockchain.fetch_transaction(" << encode_hash(tx_hash) << ")";

    node.chain().fetch_transaction(tx_hash,
        std::bind(transaction_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_last_height(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (!data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    node.chain().fetch_last_height(
        std::bind(&blockchain::last_height_fetched,
            _1, _2, request, handler));
}

void blockchain::last_height_fetched(const code& ec, size_t last_height,
    const message& request, send_handler handler)
{
    BITCOIN_ASSERT(last_height <= max_uint32);
    auto last_height32 = static_cast<uint32_t>(last_height);

    // [ code:4 ]
    // [ heigh:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(last_height32)
    });

    handler(message(request, result));
}

void blockchain::fetch_block_header(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.size() == hash_size)
        blockchain::fetch_block_header_by_hash(node, request, handler);
    else if (data.size() == sizeof(uint32_t))
        blockchain::fetch_block_header_by_height(node, request, handler);
    else
        handler(message(request, error::bad_stream));
}

void blockchain::fetch_block_header_by_hash(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == hash_size);

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();

    node.chain().fetch_block_header(block_hash,
        std::bind(&blockchain::block_header_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_block_header_by_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == sizeof(uint32_t));

    auto deserial = make_deserializer(data.begin(), data.end());
    const uint64_t height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_block_header(height,
        std::bind(&blockchain::block_header_fetched,
            _1, _2, request, handler));
}

void blockchain::block_header_fetched(const code& ec,
    const chain::header& block, const message& request, send_handler handler)
{
    // [ code:4 ]
    // [ block... ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        block.to_data(false)
    });

    handler(message(request, result));
}

void blockchain::fetch_block_transaction_hashes(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() == hash_size)
        fetch_block_transaction_hashes_by_hash(node, request, handler);
    else if (data.size() == sizeof(uint32_t))
        fetch_block_transaction_hashes_by_height(node, request, handler);
    else
        handler(message(request, error::bad_stream));
}

void blockchain::fetch_block_transaction_hashes_by_hash(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == hash_size);

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();
    node.chain().fetch_block_transaction_hashes(block_hash,
        std::bind(&blockchain::block_transaction_hashes_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_block_transaction_hashes_by_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == sizeof(uint32_t));

    auto deserial = make_deserializer(data.begin(), data.end());
    const size_t block_height = deserial.read_4_bytes_little_endian();
    node.chain().fetch_block_transaction_hashes(block_height,
        std::bind(&blockchain::block_transaction_hashes_fetched,
            _1, _2, request, handler));
}

void blockchain::block_transaction_hashes_fetched(const code& ec,
    const hash_list& hashes, const message& request, send_handler handler)
{
    // [ code:4 ]
    // [[ hash:32 ]...]
    data_chunk result(code_size + hash_size * hashes.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& tx_hash: hashes)
        serial.write_hash(tx_hash);

    handler(message(request, result));
}

void blockchain::fetch_transaction_index(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != hash_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto tx_hash = deserial.read_hash();

    node.chain().fetch_transaction_index(tx_hash,
        std::bind(&blockchain::transaction_index_fetched,
            _1, _2, _3, request, handler));
}

void blockchain::transaction_index_fetched(const code& ec, size_t block_height,
    size_t index, const message& request, send_handler handler)
{
    BITCOIN_ASSERT(index <= max_uint32);
    BITCOIN_ASSERT(block_height <= max_uint32);

    auto index32 = static_cast<uint32_t>(index);
    auto block_height32 = static_cast<uint32_t>(block_height);

    // [ code:4 ]
    // [ block_height:32 ]
    // [ tx_index:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(block_height32),
        to_little_endian(index32)
    });

    handler(message(request, result));
}

void blockchain::fetch_spend(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != point_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    using namespace boost::iostreams;
    static const auto fail_bit = stream<byte_source<data_chunk>>::failbit;
    stream<byte_source<data_chunk>> istream(data);
    istream.exceptions(fail_bit);
    chain::output_point outpoint;
    outpoint.from_data(istream);

    node.chain().fetch_spend(outpoint,
        std::bind(&blockchain::spend_fetched,
            _1, _2, request, handler));
}

void blockchain::spend_fetched(const code& ec, const chain::input_point& inpoint,
    const message& request, send_handler handler)
{
    // [ code:4 ]
    // [ hash:32 ]
    // [ index:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        inpoint.to_data()
    });

    handler(message(request, result));
}

void blockchain::fetch_block_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != hash_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();
    node.chain().fetch_block_height(block_hash,
        std::bind(&blockchain::block_height_fetched,
            _1, _2, request, handler));
}

void blockchain::block_height_fetched(const code& ec, size_t block_height,
    const message& request, send_handler handler)
{
    BITCOIN_ASSERT(block_height <= max_uint32);
    auto block_height32 = static_cast<uint32_t>(block_height);

    // [ code:4 ]
    // [ height:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(block_height32)
    });

    handler(message(request, result));
}

void blockchain::fetch_stealth(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());

    // number_bits
    const auto bitsize = deserial.read_byte();

    if (data.size() != sizeof(uint8_t) + binary::blocks_size(bitsize) +
        sizeof(uint32_t))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    // actual bitfield data
    const auto blocks = deserial.read_data(binary::blocks_size(bitsize));
    const binary prefix(bitsize, blocks);

    // from_height
    const uint64_t from_height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_stealth(prefix, from_height,
        std::bind(&blockchain::stealth_fetched,
            _1, _2, request, handler));
}

void blockchain::stealth_fetched(const code& ec,
    const stealth_compact::list& stealth_results, const message& request,
    send_handler handler)
{
    static constexpr size_t row_size = hash_size + short_hash_size + hash_size;

    // [ code:4 ]
    // [[ ephemeral_key_hash:32 ][ address_hash:20 ][ tx_hash:32 ]...]
    data_chunk result(code_size + row_size * stealth_results.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& row: stealth_results)
    {
        serial.write_hash(row.ephemeral_public_key_hash);
        serial.write_short_hash(row.public_key_hash);
        serial.write_hash(row.transaction_hash);
    }

    handler(message(request, result));
}

void blockchain::fetch_stealth2(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());

    // number_bits
    const auto bitsize = deserial.read_byte();

    if (data.size() != sizeof(uint8_t) + binary::blocks_size(bitsize) +
        sizeof(uint32_t))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    // actual bitfield data
    const auto blocks = deserial.read_data(binary::blocks_size(bitsize));
    const binary prefix(bitsize, blocks);

    // from_height
    const uint64_t from_height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_stealth(prefix, from_height,
        std::bind(&blockchain::stealth_fetched2,
            _1, _2, request, handler));
}

void blockchain::stealth_fetched2(const code& ec,
    const stealth_compact::list& stealth_results, const message& request,
    send_handler handler)
{
    // [ code:4 ]
    // [[ tx_hash:32 ]...]
    data_chunk result(code_size + hash_size * stealth_results.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& row: stealth_results)
        serial.write_hash(row.transaction_hash);

    handler(message(request, result));
}

} // namespace server
} // namespace libbitcoin
<commit_msg>Avoid bogus compound words (style).<commit_after>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin-server.
 *
 * libbitcoin-server 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 <bitcoin/server/interface/blockchain.hpp>

#include <cstdint>
#include <cstddef>
#include <functional>
#include <bitcoin/blockchain.hpp>
#include <bitcoin/server/define.hpp>
#include <bitcoin/server/messages/message.hpp>
#include <bitcoin/server/server_node.hpp>
#include <bitcoin/server/utility/fetch_helpers.hpp>

namespace libbitcoin {
namespace server {

using namespace std::placeholders;
using namespace bc::blockchain;
using namespace bc::chain;
using namespace bc::wallet;

void blockchain::fetch_history(server_node& node, const message& request,
    send_handler handler)
{
    static constexpr uint64_t limit = 0;
    uint32_t from_height;
    payment_address address;

    if (!unwrap_fetch_history_args(address, from_height, request))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    log::debug(LOG_SERVER)
        << "blockchain.fetch_history(" << address.encoded()
        << ", from_height=" << from_height << ")";

    node.chain().fetch_history(address, limit, from_height,
        std::bind(send_history_result,
            _1, _2, request, handler));
}

void blockchain::fetch_transaction(server_node& node, const message& request,
    send_handler handler)
{
    hash_digest tx_hash;

    if (!unwrap_fetch_transaction_args(tx_hash, request))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    log::debug(LOG_SERVER)
        << "blockchain.fetch_transaction(" << encode_hash(tx_hash) << ")";

    node.chain().fetch_transaction(tx_hash,
        std::bind(transaction_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_last_height(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (!data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    node.chain().fetch_last_height(
        std::bind(&blockchain::last_height_fetched,
            _1, _2, request, handler));
}

void blockchain::last_height_fetched(const code& ec, size_t last_height,
    const message& request, send_handler handler)
{
    BITCOIN_ASSERT(last_height <= max_uint32);
    auto last_height32 = static_cast<uint32_t>(last_height);

    // [ code:4 ]
    // [ heigh:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(last_height32)
    });

    handler(message(request, result));
}

void blockchain::fetch_block_header(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.size() == hash_size)
        blockchain::fetch_block_header_by_hash(node, request, handler);
    else if (data.size() == sizeof(uint32_t))
        blockchain::fetch_block_header_by_height(node, request, handler);
    else
        handler(message(request, error::bad_stream));
}

void blockchain::fetch_block_header_by_hash(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == hash_size);

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();

    node.chain().fetch_block_header(block_hash,
        std::bind(&blockchain::block_header_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_block_header_by_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == sizeof(uint32_t));

    auto deserial = make_deserializer(data.begin(), data.end());
    const uint64_t height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_block_header(height,
        std::bind(&blockchain::block_header_fetched,
            _1, _2, request, handler));
}

void blockchain::block_header_fetched(const code& ec,
    const chain::header& block, const message& request, send_handler handler)
{
    // [ code:4 ]
    // [ block... ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        block.to_data(false)
    });

    handler(message(request, result));
}

void blockchain::fetch_block_transaction_hashes(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() == hash_size)
        fetch_block_transaction_hashes_by_hash(node, request, handler);
    else if (data.size() == sizeof(uint32_t))
        fetch_block_transaction_hashes_by_height(node, request, handler);
    else
        handler(message(request, error::bad_stream));
}

void blockchain::fetch_block_transaction_hashes_by_hash(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == hash_size);

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();
    node.chain().fetch_block_transaction_hashes(block_hash,
        std::bind(&blockchain::block_transaction_hashes_fetched,
            _1, _2, request, handler));
}

void blockchain::fetch_block_transaction_hashes_by_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();
    BITCOIN_ASSERT(data.size() == sizeof(uint32_t));

    auto deserial = make_deserializer(data.begin(), data.end());
    const size_t block_height = deserial.read_4_bytes_little_endian();
    node.chain().fetch_block_transaction_hashes(block_height,
        std::bind(&blockchain::block_transaction_hashes_fetched,
            _1, _2, request, handler));
}

void blockchain::block_transaction_hashes_fetched(const code& ec,
    const hash_list& hashes, const message& request, send_handler handler)
{
    // [ code:4 ]
    // [[ hash:32 ]...]
    data_chunk result(code_size + hash_size * hashes.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& tx_hash: hashes)
        serial.write_hash(tx_hash);

    handler(message(request, result));
}

void blockchain::fetch_transaction_index(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != hash_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto tx_hash = deserial.read_hash();

    node.chain().fetch_transaction_index(tx_hash,
        std::bind(&blockchain::transaction_index_fetched,
            _1, _2, _3, request, handler));
}

void blockchain::transaction_index_fetched(const code& ec, size_t block_height,
    size_t index, const message& request, send_handler handler)
{
    BITCOIN_ASSERT(index <= max_uint32);
    BITCOIN_ASSERT(block_height <= max_uint32);

    auto index32 = static_cast<uint32_t>(index);
    auto block_height32 = static_cast<uint32_t>(block_height);

    // [ code:4 ]
    // [ block_height:32 ]
    // [ tx_index:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(block_height32),
        to_little_endian(index32)
    });

    handler(message(request, result));
}

void blockchain::fetch_spend(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != point_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    using namespace boost::iostreams;
    static const auto fail_bit = stream<byte_source<data_chunk>>::failbit;
    stream<byte_source<data_chunk>> istream(data);
    istream.exceptions(fail_bit);
    chain::output_point outpoint;
    outpoint.from_data(istream);

    node.chain().fetch_spend(outpoint,
        std::bind(&blockchain::spend_fetched,
            _1, _2, request, handler));
}

void blockchain::spend_fetched(const code& ec, const chain::input_point& inpoint,
    const message& request, send_handler handler)
{
    // [ code:4 ]
    // [ hash:32 ]
    // [ index:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        inpoint.to_data()
    });

    handler(message(request, result));
}

void blockchain::fetch_block_height(server_node& node,
    const message& request, send_handler handler)
{
    const auto& data = request.data();

    if (data.size() != hash_size)
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());
    const auto block_hash = deserial.read_hash();
    node.chain().fetch_block_height(block_hash,
        std::bind(&blockchain::block_height_fetched,
            _1, _2, request, handler));
}

void blockchain::block_height_fetched(const code& ec, size_t block_height,
    const message& request, send_handler handler)
{
    BITCOIN_ASSERT(block_height <= max_uint32);
    auto block_height32 = static_cast<uint32_t>(block_height);

    // [ code:4 ]
    // [ height:4 ]
    const auto result = build_chunk(
    {
        message::to_bytes(ec),
        to_little_endian(block_height32)
    });

    handler(message(request, result));
}

void blockchain::fetch_stealth(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());

    // number_bits
    const auto bit_size = deserial.read_byte();

    if (data.size() != sizeof(uint8_t) + binary::blocks_size(bit_size) +
        sizeof(uint32_t))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    // actual bitfield data
    const auto blocks = deserial.read_data(binary::blocks_size(bit_size));
    const binary prefix(bit_size, blocks);

    // from_height
    const uint64_t from_height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_stealth(prefix, from_height,
        std::bind(&blockchain::stealth_fetched,
            _1, _2, request, handler));
}

void blockchain::stealth_fetched(const code& ec,
    const stealth_compact::list& stealth_results, const message& request,
    send_handler handler)
{
    static constexpr size_t row_size = hash_size + short_hash_size + hash_size;

    // [ code:4 ]
    // [[ ephemeral_key_hash:32 ][ address_hash:20 ][ tx_hash:32 ]...]
    data_chunk result(code_size + row_size * stealth_results.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& row: stealth_results)
    {
        serial.write_hash(row.ephemeral_public_key_hash);
        serial.write_short_hash(row.public_key_hash);
        serial.write_hash(row.transaction_hash);
    }

    handler(message(request, result));
}

void blockchain::fetch_stealth2(server_node& node, const message& request,
    send_handler handler)
{
    const auto& data = request.data();

    if (data.empty())
    {
        handler(message(request, error::bad_stream));
        return;
    }

    auto deserial = make_deserializer(data.begin(), data.end());

    // number_bits
    const auto bit_size = deserial.read_byte();

    if (data.size() != sizeof(uint8_t) + binary::blocks_size(bit_size) +
        sizeof(uint32_t))
    {
        handler(message(request, error::bad_stream));
        return;
    }

    // actual bitfield data
    const auto blocks = deserial.read_data(binary::blocks_size(bit_size));
    const binary prefix(bit_size, blocks);

    // from_height
    const uint64_t from_height = deserial.read_4_bytes_little_endian();

    node.chain().fetch_stealth(prefix, from_height,
        std::bind(&blockchain::stealth_fetched2,
            _1, _2, request, handler));
}

void blockchain::stealth_fetched2(const code& ec,
    const stealth_compact::list& stealth_results, const message& request,
    send_handler handler)
{
    // [ code:4 ]
    // [[ tx_hash:32 ]...]
    data_chunk result(code_size + hash_size * stealth_results.size());
    auto serial = make_serializer(result.begin());
    serial.write_error_code(ec);

    for (const auto& row: stealth_results)
        serial.write_hash(row.transaction_hash);

    handler(message(request, result));
}

} // namespace server
} // namespace libbitcoin
<|endoftext|>


<commit_before>/*
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
 */

#include "locator/gossiping_property_file_snitch.hh"
#include "gms/versioned_value.hh"
#include "message/msg_addr.hh"
#include "message/messaging_service.hh"
#include "gms/gossiper.hh"

namespace locator {
future<bool> gossiping_property_file_snitch::property_file_was_modified() {
    return open_file_dma(_prop_file_name, open_flags::ro)
    .then([this](file f) {
        return do_with(std::move(f), [] (file& f) {
            return f.stat();
        });
    }).then_wrapped([this] (auto&& f) {
        try {
            auto st = f.get0();

            if (!_last_file_mod ||
                _last_file_mod->tv_sec != st.st_mtim.tv_sec) {
                _last_file_mod = st.st_mtim;
                return true;
            } else {
                return false;
            }
        } catch (...) {
            logger().error("Failed to open {} for read or to get stats", _prop_file_name);
            throw;
        }
    });
}

gossiping_property_file_snitch::gossiping_property_file_snitch(
    const sstring& fname, unsigned io_cpuid)
: production_snitch_base(fname), _file_reader_cpu_id(io_cpuid) {
    if (this_shard_id() == _file_reader_cpu_id) {
        io_cpu_id() = _file_reader_cpu_id;
    }
}

future<> gossiping_property_file_snitch::start() {
    using namespace std::chrono_literals;

    _state = snitch_state::initializing;

    reset_io_state();

    // Run a timer only on specific CPU
    if (this_shard_id() == _file_reader_cpu_id) {
        //
        // Here we will create a timer that will read the properties file every
        // minute and load its contents into the gossiper.endpoint_state_map
        //
        _file_reader.set_callback([this] {
            periodic_reader_callback();
        });

        return read_property_file().then([this] {
            start_io();
            set_snitch_ready();
            return make_ready_future<>();
        });
    }

    set_snitch_ready();
    return make_ready_future<>();
}

void gossiping_property_file_snitch::periodic_reader_callback() {
    _file_reader_runs = true;
    //FIXME: discarded future.
    (void)property_file_was_modified().then([this] (bool was_modified) {

        if (was_modified) {
            return read_property_file();
        }

        return make_ready_future<>();
    }).then_wrapped([this] (auto&& f) {
        try {
            f.get();
        } catch (...) {
            logger().error("Exception has been thrown when parsing the property file.");
        }

        if (_state == snitch_state::stopping || _state == snitch_state::io_pausing) {
            this->set_stopped();
        } else if (_state != snitch_state::stopped) {
            _file_reader.arm(reload_property_file_period());
        }

        _file_reader_runs = false;
    });
}

future<> gossiping_property_file_snitch::gossiper_starting() {
    //
    // Note: currently gossiper "main" instance always runs on CPU0 therefore
    // this function will be executed on CPU0 only.
    //
        _gossip_started = true;
        return reload_gossiper_state();
}

std::list<std::pair<gms::application_state, gms::versioned_value>> gossiping_property_file_snitch::get_app_states() const {
    sstring ip = format("{}", gms::get_local_gossiper().get_local_messaging().listen_address());
    return {
        {gms::application_state::DC, gms::versioned_value::datacenter(_my_dc)},
        {gms::application_state::RACK, gms::versioned_value::rack(_my_rack)},
        {gms::application_state::INTERNAL_IP, gms::versioned_value::internal_ip(std::move(ip))},
    };
}

future<> gossiping_property_file_snitch::read_property_file() {
    using namespace exceptions;

    return load_property_file().then([this] {
        return reload_configuration();
    }).then_wrapped([this] (auto&& f) {
        try {
            f.get();
            return make_ready_future<>();
        } catch (...) {
            //
            // In case of an error:
            //    - Halt if in the constructor.
            //    - Print an error when reloading.
            //
            if (_state == snitch_state::initializing) {
                logger().error("Failed to parse a properties file ({}). Halting...", _prop_file_name);
                throw;
            } else {
                logger().warn("Failed to reload a properties file ({}). Using previous values.", _prop_file_name);
                return make_ready_future<>();
            }
        }
    });
}

future<> gossiping_property_file_snitch::reload_configuration() {
    // "prefer_local" is FALSE by default
    bool new_prefer_local = false;
    sstring new_dc;
    sstring new_rack;

    // Rack and Data Center have to be defined in the properties file!
    if (!_prop_values.contains(dc_property_key) || !_prop_values.contains(rack_property_key)) {
        throw_incomplete_file();
    }

    new_dc   = _prop_values[dc_property_key];
    new_rack = _prop_values[rack_property_key];

    if (_prop_values.contains(prefer_local_property_key)) {
        if (_prop_values[prefer_local_property_key] == "false") {
            new_prefer_local = false;
        } else if (_prop_values[prefer_local_property_key] == "true") {
            new_prefer_local = true;
        } else {
            throw_bad_format("prefer_local configuration is malformed");
        }
    }

    if (_state == snitch_state::initializing || _my_dc != new_dc ||
        _my_rack != new_rack || _prefer_local != new_prefer_local) {

        _my_dc = new_dc;
        _my_rack = new_rack;
        _prefer_local = new_prefer_local;

        assert(_my_distributed);

        return _my_distributed->invoke_on_all(
            [this] (snitch_ptr& local_s) {

            // Distribute the new values on all CPUs but the current one
            if (this_shard_id() != _file_reader_cpu_id) {
                local_s->set_my_dc(_my_dc);
                local_s->set_my_rack(_my_rack);
                local_s->set_prefer_local(_prefer_local);
            }
        }).then([this] {
            return seastar::async([this] {
                // reload Gossiper state (executed on CPU0 only)
                _my_distributed->invoke_on(0, [] (snitch_ptr& local_snitch_ptr) {
                    return local_snitch_ptr->reload_gossiper_state();
                }).get();

                _reconfigured();

                // spread the word...
                _my_distributed->invoke_on(0, [] (snitch_ptr& local_snitch_ptr) {
                    if (local_snitch_ptr->local_gossiper_started()) {
                        return local_snitch_ptr->gossip_snitch_info({});
                    }

                    return make_ready_future<>();
                }).get();
            });
        });
    }

    return make_ready_future<>();
}

void gossiping_property_file_snitch::set_stopped() {
    if (_state == snitch_state::stopping) {
        _state = snitch_state::stopped;
    } else {
        _state = snitch_state::io_paused;
    }

    _io_is_stopped.set_value();
}

future<> gossiping_property_file_snitch::stop_io() {
    if (this_shard_id() == _file_reader_cpu_id) {
        _file_reader.cancel();

        // If timer is not running then set the STOPPED state right away.
        if (!_file_reader_runs) {
            set_stopped();
        }
    } else {
        set_stopped();
    }

    return _io_is_stopped.get_future();
}

void gossiping_property_file_snitch::resume_io() {
    reset_io_state();
    start_io();
    set_snitch_ready();
}

void gossiping_property_file_snitch::start_io() {
    // Run a timer only on specific CPU
    if (this_shard_id() == _file_reader_cpu_id) {
        _file_reader.arm(reload_property_file_period());
    }
}

future<> gossiping_property_file_snitch::stop() {
    if (_state == snitch_state::stopped || _state == snitch_state::io_paused) {
        return make_ready_future<>();
    }

    _state = snitch_state::stopping;

    return stop_io();
}

future<> gossiping_property_file_snitch::pause_io() {
    if (_state == snitch_state::stopped || _state == snitch_state::io_paused) {
        return make_ready_future<>();
    }

    _state = snitch_state::io_pausing;

    return stop_io();
}

// should be invoked of CPU0 only
future<> gossiping_property_file_snitch::reload_gossiper_state() {
    if (!_gossip_started) {
        return make_ready_future<>();
    }

    future<> ret = make_ready_future<>();
    if (_reconnectable_helper) {
        ret = gms::get_local_gossiper().unregister_(_reconnectable_helper);
    }

    if (!_prefer_local) {
        return ret;
    }

    return ret.then([this] {
        _reconnectable_helper = ::make_shared<reconnectable_snitch_helper>(_my_dc);
        gms::get_local_gossiper().register_(_reconnectable_helper);
    });
}

using registry_2_params = class_registrator<i_endpoint_snitch,
                                   gossiping_property_file_snitch,
                                   const sstring&, unsigned>;
static registry_2_params registrator2("org.apache.cassandra.locator.GossipingPropertyFileSnitch");

using registry_1_param = class_registrator<i_endpoint_snitch,
                                   gossiping_property_file_snitch,
                                   const sstring&>;
static registry_1_param registrator1("org.apache.cassandra.locator.GossipingPropertyFileSnitch");

using registry_default = class_registrator<i_endpoint_snitch,
                                           gossiping_property_file_snitch>;
static registry_default registrator_default("org.apache.cassandra.locator.GossipingPropertyFileSnitch");
static registry_default registrator_default_short_name("GossipingPropertyFileSnitch");
} // namespace locator
<commit_msg>property-file snitch: Reload state in .start()<commit_after>/*
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
 */

#include "locator/gossiping_property_file_snitch.hh"
#include "gms/versioned_value.hh"
#include "message/msg_addr.hh"
#include "message/messaging_service.hh"
#include "gms/gossiper.hh"

namespace locator {
future<bool> gossiping_property_file_snitch::property_file_was_modified() {
    return open_file_dma(_prop_file_name, open_flags::ro)
    .then([this](file f) {
        return do_with(std::move(f), [] (file& f) {
            return f.stat();
        });
    }).then_wrapped([this] (auto&& f) {
        try {
            auto st = f.get0();

            if (!_last_file_mod ||
                _last_file_mod->tv_sec != st.st_mtim.tv_sec) {
                _last_file_mod = st.st_mtim;
                return true;
            } else {
                return false;
            }
        } catch (...) {
            logger().error("Failed to open {} for read or to get stats", _prop_file_name);
            throw;
        }
    });
}

gossiping_property_file_snitch::gossiping_property_file_snitch(
    const sstring& fname, unsigned io_cpuid)
: production_snitch_base(fname), _file_reader_cpu_id(io_cpuid) {
    if (this_shard_id() == _file_reader_cpu_id) {
        io_cpu_id() = _file_reader_cpu_id;
    }
}

future<> gossiping_property_file_snitch::start() {
    using namespace std::chrono_literals;

    _state = snitch_state::initializing;

    reset_io_state();

    // Run a timer only on specific CPU
    if (this_shard_id() == _file_reader_cpu_id) {
        //
        // Here we will create a timer that will read the properties file every
        // minute and load its contents into the gossiper.endpoint_state_map
        //
        _file_reader.set_callback([this] {
            periodic_reader_callback();
        });

        return read_property_file().then([this] {
            start_io();
            set_snitch_ready();
            return make_ready_future<>();
        });
    }

    set_snitch_ready();
    return make_ready_future<>();
}

void gossiping_property_file_snitch::periodic_reader_callback() {
    _file_reader_runs = true;
    //FIXME: discarded future.
    (void)property_file_was_modified().then([this] (bool was_modified) {

        if (was_modified) {
            return read_property_file();
        }

        return make_ready_future<>();
    }).then_wrapped([this] (auto&& f) {
        try {
            f.get();
        } catch (...) {
            logger().error("Exception has been thrown when parsing the property file.");
        }

        if (_state == snitch_state::stopping || _state == snitch_state::io_pausing) {
            this->set_stopped();
        } else if (_state != snitch_state::stopped) {
            _file_reader.arm(reload_property_file_period());
        }

        _file_reader_runs = false;
    });
}

future<> gossiping_property_file_snitch::gossiper_starting() {
    //
    // Note: currently gossiper "main" instance always runs on CPU0 therefore
    // this function will be executed on CPU0 only.
    //
        _gossip_started = true;
        return make_ready_future<>();
}

std::list<std::pair<gms::application_state, gms::versioned_value>> gossiping_property_file_snitch::get_app_states() const {
    sstring ip = format("{}", gms::get_local_gossiper().get_local_messaging().listen_address());
    return {
        {gms::application_state::DC, gms::versioned_value::datacenter(_my_dc)},
        {gms::application_state::RACK, gms::versioned_value::rack(_my_rack)},
        {gms::application_state::INTERNAL_IP, gms::versioned_value::internal_ip(std::move(ip))},
    };
}

future<> gossiping_property_file_snitch::read_property_file() {
    using namespace exceptions;

    return load_property_file().then([this] {
        return reload_configuration();
    }).then_wrapped([this] (auto&& f) {
        try {
            f.get();
            return make_ready_future<>();
        } catch (...) {
            //
            // In case of an error:
            //    - Halt if in the constructor.
            //    - Print an error when reloading.
            //
            if (_state == snitch_state::initializing) {
                logger().error("Failed to parse a properties file ({}). Halting...", _prop_file_name);
                throw;
            } else {
                logger().warn("Failed to reload a properties file ({}). Using previous values.", _prop_file_name);
                return make_ready_future<>();
            }
        }
    });
}

future<> gossiping_property_file_snitch::reload_configuration() {
    // "prefer_local" is FALSE by default
    bool new_prefer_local = false;
    sstring new_dc;
    sstring new_rack;

    // Rack and Data Center have to be defined in the properties file!
    if (!_prop_values.contains(dc_property_key) || !_prop_values.contains(rack_property_key)) {
        throw_incomplete_file();
    }

    new_dc   = _prop_values[dc_property_key];
    new_rack = _prop_values[rack_property_key];

    if (_prop_values.contains(prefer_local_property_key)) {
        if (_prop_values[prefer_local_property_key] == "false") {
            new_prefer_local = false;
        } else if (_prop_values[prefer_local_property_key] == "true") {
            new_prefer_local = true;
        } else {
            throw_bad_format("prefer_local configuration is malformed");
        }
    }

    if (_state == snitch_state::initializing || _my_dc != new_dc ||
        _my_rack != new_rack || _prefer_local != new_prefer_local) {

        _my_dc = new_dc;
        _my_rack = new_rack;
        _prefer_local = new_prefer_local;

        assert(_my_distributed);

        return _my_distributed->invoke_on_all(
            [this] (snitch_ptr& local_s) {

            // Distribute the new values on all CPUs but the current one
            if (this_shard_id() != _file_reader_cpu_id) {
                local_s->set_my_dc(_my_dc);
                local_s->set_my_rack(_my_rack);
                local_s->set_prefer_local(_prefer_local);
            }
        }).then([this] {
            // FIXME -- tests don't start gossiper
            if (!gms::get_gossiper().local_is_initialized()) {
                return make_ready_future<>();
            }

            return seastar::async([this] {
                // reload Gossiper state (executed on CPU0 only)
                _my_distributed->invoke_on(0, [] (snitch_ptr& local_snitch_ptr) {
                    return local_snitch_ptr->reload_gossiper_state();
                }).get();

                _reconfigured();

                // spread the word...
                _my_distributed->invoke_on(0, [] (snitch_ptr& local_snitch_ptr) {
                    if (local_snitch_ptr->local_gossiper_started()) {
                        return local_snitch_ptr->gossip_snitch_info({});
                    }

                    return make_ready_future<>();
                }).get();
            });
        });
    }

    return make_ready_future<>();
}

void gossiping_property_file_snitch::set_stopped() {
    if (_state == snitch_state::stopping) {
        _state = snitch_state::stopped;
    } else {
        _state = snitch_state::io_paused;
    }

    _io_is_stopped.set_value();
}

future<> gossiping_property_file_snitch::stop_io() {
    if (this_shard_id() == _file_reader_cpu_id) {
        _file_reader.cancel();

        // If timer is not running then set the STOPPED state right away.
        if (!_file_reader_runs) {
            set_stopped();
        }
    } else {
        set_stopped();
    }

    return _io_is_stopped.get_future();
}

void gossiping_property_file_snitch::resume_io() {
    reset_io_state();
    start_io();
    set_snitch_ready();
}

void gossiping_property_file_snitch::start_io() {
    // Run a timer only on specific CPU
    if (this_shard_id() == _file_reader_cpu_id) {
        _file_reader.arm(reload_property_file_period());
    }
}

future<> gossiping_property_file_snitch::stop() {
    if (_state == snitch_state::stopped || _state == snitch_state::io_paused) {
        return make_ready_future<>();
    }

    _state = snitch_state::stopping;

    return stop_io();
}

future<> gossiping_property_file_snitch::pause_io() {
    if (_state == snitch_state::stopped || _state == snitch_state::io_paused) {
        return make_ready_future<>();
    }

    _state = snitch_state::io_pausing;

    return stop_io();
}

// should be invoked of CPU0 only
future<> gossiping_property_file_snitch::reload_gossiper_state() {
    future<> ret = make_ready_future<>();
    if (_reconnectable_helper) {
        ret = gms::get_local_gossiper().unregister_(_reconnectable_helper);
    }

    if (!_prefer_local) {
        return ret;
    }

    return ret.then([this] {
        _reconnectable_helper = ::make_shared<reconnectable_snitch_helper>(_my_dc);
        gms::get_local_gossiper().register_(_reconnectable_helper);
    });
}

using registry_2_params = class_registrator<i_endpoint_snitch,
                                   gossiping_property_file_snitch,
                                   const sstring&, unsigned>;
static registry_2_params registrator2("org.apache.cassandra.locator.GossipingPropertyFileSnitch");

using registry_1_param = class_registrator<i_endpoint_snitch,
                                   gossiping_property_file_snitch,
                                   const sstring&>;
static registry_1_param registrator1("org.apache.cassandra.locator.GossipingPropertyFileSnitch");

using registry_default = class_registrator<i_endpoint_snitch,
                                           gossiping_property_file_snitch>;
static registry_default registrator_default("org.apache.cassandra.locator.GossipingPropertyFileSnitch");
static registry_default registrator_default_short_name("GossipingPropertyFileSnitch");
} // namespace locator
<|endoftext|>


<commit_before>/*
    addcontactwizard.cpp - Kopete's Add Contact Wizard

    Copyright (c) 2002 by Nick Betcher           <nbetcher@kde.org>
    Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

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

#include <qlayout.h>

#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <kpushbutton.h>
#include <kstandarddirs.h>

#include "addcontactpage.h"
#include "addcontactwizard.h"
#include "kopetegroup.h"
#include "kopetecontactlist.h"
#include "kopeteprotocol.h"
#include "pluginloader.h"
#include "protocolboxitem.h"
#include "kopetemetacontact.h"

AddContactWizard::AddContactWizard( QWidget *parent, const char *name )
: AddContactWizard_Base( parent, name )
{
	QStringList groups =KopeteContactList::contactList()->groups().toStringList();

	QStringList::ConstIterator it = groups.begin();
	for( ; it != groups.end(); ++it )
	{
		QString groupname = *it;

		if ( !groupname.isNull() )
			new QCheckListItem( groupList, groupname, QCheckListItem::CheckBox);
	}

	int pluginCount = 0;
	ProtocolBoxItem *pluginItem = 0L;

	QValueList<KopeteLibraryInfo> l = LibraryLoader::pluginLoader()->loaded();
	for (QValueList<KopeteLibraryInfo>::Iterator i = l.begin(); i != l.end(); ++i)
	{
//		kdDebug() << "AddContactWizard::AddContactWizard :" <<(*i).name << " " << (*i).specfile <<"\n";
		KopetePlugin *tmpprot = LibraryLoader::pluginLoader()->searchByName( (*i).name );
		KopeteProtocol *prot = dynamic_cast<KopeteProtocol*>( tmpprot );

		if (prot)
		{
			pluginItem = new ProtocolBoxItem( protocolListView, (*i).name );
			pluginItem->protocol = prot;
			pluginCount++;
		}
	}

	if ( pluginCount == 1 )
		pluginItem->setOn( true );

	setNextEnabled(page3, (pluginCount == 1));
	setFinishEnabled(page4, true);

	connect( addGroupButton, SIGNAL(clicked()) , SLOT(slotAddGroupClicked()) );
	connect( protocolListView, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
}

AddContactWizard::~AddContactWizard()
{
}

void AddContactWizard::slotProtocolListClicked( QListViewItem *)
{
	// Just makes sure a protocol is selected before allowing the user to continue
	bool oneIsChecked = false;
	for (QListViewItem *listItem = protocolListView->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotProtocolListClicked : one listItem is not a CheckListItem" << endl;
		}
		else if (check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}
	setNextEnabled(page3,oneIsChecked);
}

void AddContactWizard::slotGroupListClicked( QListViewItem *)
{
	//top-level contacts are allowed
/*
	bool oneIsChecked = false;
	for (QListViewItem *listItem = groupList->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotGroupListClicked : one listItem is not a CheckListItem" << endl;
		}
		else 	if (check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}
	setNextEnabled(page2,oneIsChecked);
  */
}

void AddContactWizard::slotAddGroupClicked()
{
	bool ok;
	QString groupName = KLineEditDlg::getText(
		i18n( "New Group - Kopete" ),
		i18n( "Please enter the name for the new group" ),
		QString::null, &ok );

	if ( !groupName.isNull() && ok)
		new QCheckListItem( groupList, groupName, QCheckListItem::CheckBox);

}

void AddContactWizard::slotRemoveGroupClicked()
{
}

void AddContactWizard::accept()
{
	KopeteMetaContact *m=new KopeteMetaContact();

	for (QListViewItem *listItem = groupList->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotGroupListClicked : one listItem is not a CheckListItem" << endl;
		}
		else 	if (check->isOn())
		{
			m->addToGroup(KopeteContactList::contactList()->getGroup(check->text()));
		}
	}

	for (AddContactPage *ePage = protocolPages.first(); ePage ; ePage = protocolPages.next())
	{
		ePage->slotFinish(m);
	}
	KopeteContactList::contactList()->addMetaContact(m);
	delete(this);
}

void AddContactWizard::next()
{
	if (currentPage() == page3)
	{

		for (AddContactPage *ePage = protocolPages.first(); ePage != 0; ePage = protocolPages.first())
		{
			protocolPages.remove(ePage);
			if(ePage) delete ePage;
		}

		// We don't keep track of this pointer because it gets deleted when the wizard does (which is what we want)
		for (ProtocolBoxItem *item = dynamic_cast<ProtocolBoxItem *>(protocolListView->firstChild()); item != 0; item = dynamic_cast<ProtocolBoxItem *>(item->itemBelow()))
		{
			if (!item) break; // this shouldn't happen
			if (item->isOn())
			{
				if (!item->protocol) break; // this shouldn't happen either, but I hate crashes
				AddContactPage *addPage = item->protocol->createAddContactWidget(this);
				if (!addPage) break;
				QString title = i18n( "The protocol name is prepended here",
					"%1 protocol contact information" ).arg( item->text() );
				addPage->show();
				insertPage(addPage, title, indexOf(page4));
				protocolPages.append(addPage);
			}
		}
		QWizard::next();
		return;
	}
	if (currentPage() != page1 && currentPage() != page2 && currentPage() != page3 && currentPage() != page4)
	{
		AddContactPage *ePage = dynamic_cast<AddContactPage *>(currentPage());
		if (!ePage) return;
		if (!ePage->validateData())
			return;
		QWizard::next();
		return;
	}
	QWizard::next();
}

#include "addcontactwizard.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>Use the plugin list from the plugin loader, not the one returning PluginLoader's internals.<commit_after>/*
    addcontactwizard.cpp - Kopete's Add Contact Wizard

    Copyright (c) 2002 by Nick Betcher           <nbetcher@kde.org>
    Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

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

#include <qlayout.h>

#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <kpushbutton.h>
#include <kstandarddirs.h>

#include "addcontactpage.h"
#include "addcontactwizard.h"
#include "kopetegroup.h"
#include "kopetecontactlist.h"
#include "kopeteprotocol.h"
#include "pluginloader.h"
#include "protocolboxitem.h"
#include "kopetemetacontact.h"

AddContactWizard::AddContactWizard( QWidget *parent, const char *name )
: AddContactWizard_Base( parent, name )
{
	QStringList groups =KopeteContactList::contactList()->groups().toStringList();

	QStringList::ConstIterator it = groups.begin();
	for( ; it != groups.end(); ++it )
	{
		QString groupname = *it;

		if ( !groupname.isNull() )
			new QCheckListItem( groupList, groupname, QCheckListItem::CheckBox);
	}

	int pluginCount = 0;
	ProtocolBoxItem *pluginItem = 0L;

	QPtrList<KopetePlugin> plugins = LibraryLoader::pluginLoader()->plugins();
	for( KopetePlugin *p = plugins.first() ; p ; p = plugins.next() )
	{
		KopeteProtocol *proto = dynamic_cast<KopeteProtocol*>( p );
		if( proto )
		{
			pluginItem = new ProtocolBoxItem( protocolListView, proto->pluginId() );
			pluginItem->protocol = proto;
			pluginCount++;
		}
	}

	if ( pluginCount == 1 )
		pluginItem->setOn( true );

	setNextEnabled(page3, (pluginCount == 1));
	setFinishEnabled(page4, true);

	connect( addGroupButton, SIGNAL(clicked()) , SLOT(slotAddGroupClicked()) );
	connect( protocolListView, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
}

AddContactWizard::~AddContactWizard()
{
}

void AddContactWizard::slotProtocolListClicked( QListViewItem *)
{
	// Just makes sure a protocol is selected before allowing the user to continue
	bool oneIsChecked = false;
	for (QListViewItem *listItem = protocolListView->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotProtocolListClicked : one listItem is not a CheckListItem" << endl;
		}
		else if (check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}
	setNextEnabled(page3,oneIsChecked);
}

void AddContactWizard::slotGroupListClicked( QListViewItem *)
{
	//top-level contacts are allowed
/*
	bool oneIsChecked = false;
	for (QListViewItem *listItem = groupList->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotGroupListClicked : one listItem is not a CheckListItem" << endl;
		}
		else 	if (check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}
	setNextEnabled(page2,oneIsChecked);
  */
}

void AddContactWizard::slotAddGroupClicked()
{
	bool ok;
	QString groupName = KLineEditDlg::getText(
		i18n( "New Group - Kopete" ),
		i18n( "Please enter the name for the new group" ),
		QString::null, &ok );

	if ( !groupName.isNull() && ok)
		new QCheckListItem( groupList, groupName, QCheckListItem::CheckBox);

}

void AddContactWizard::slotRemoveGroupClicked()
{
}

void AddContactWizard::accept()
{
	KopeteMetaContact *m=new KopeteMetaContact();

	for (QListViewItem *listItem = groupList->firstChild(); listItem != 0; listItem = listItem->itemBelow())
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(listItem);
		if (!check)
		{
			kdDebug() << "WARNING : AddContactWizard::slotGroupListClicked : one listItem is not a CheckListItem" << endl;
		}
		else 	if (check->isOn())
		{
			m->addToGroup(KopeteContactList::contactList()->getGroup(check->text()));
		}
	}

	for (AddContactPage *ePage = protocolPages.first(); ePage ; ePage = protocolPages.next())
	{
		ePage->slotFinish(m);
	}
	KopeteContactList::contactList()->addMetaContact(m);
	delete(this);
}

void AddContactWizard::next()
{
	if (currentPage() == page3)
	{

		for (AddContactPage *ePage = protocolPages.first(); ePage != 0; ePage = protocolPages.first())
		{
			protocolPages.remove(ePage);
			if(ePage) delete ePage;
		}

		// We don't keep track of this pointer because it gets deleted when the wizard does (which is what we want)
		for (ProtocolBoxItem *item = dynamic_cast<ProtocolBoxItem *>(protocolListView->firstChild()); item != 0; item = dynamic_cast<ProtocolBoxItem *>(item->itemBelow()))
		{
			if (!item) break; // this shouldn't happen
			if (item->isOn())
			{
				if (!item->protocol) break; // this shouldn't happen either, but I hate crashes
				AddContactPage *addPage = item->protocol->createAddContactWidget(this);
				if (!addPage) break;
				QString title = i18n( "The protocol name is prepended here",
					"%1 protocol contact information" ).arg( item->text() );
				addPage->show();
				insertPage(addPage, title, indexOf(page4));
				protocolPages.append(addPage);
			}
		}
		QWizard::next();
		return;
	}
	if (currentPage() != page1 && currentPage() != page2 && currentPage() != page3 && currentPage() != page4)
	{
		AddContactPage *ePage = dynamic_cast<AddContactPage *>(currentPage());
		if (!ePage) return;
		if (!ePage->validateData())
			return;
		QWizard::next();
		return;
	}
	QWizard::next();
}

#include "addcontactwizard.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>#undef NDEBUG  //because we are using assert to check actual operations that cannot be skipped in release mode testing
#include <boost/range/irange.hpp>
#include <cassert>

#include <exodus/program.h>
programinit()

	function main() {

	// Quit if running under make since there are no tests
	if (osgetenv("MAKELEVEL")) {
		printl();
		printl("Test passed - skipped because MAKELEVEL is set");
		return 0;
	}

	printl();

	int nn = 1000000;
	var setup_time;

	bool   the_truth_hurts = false;
	double some_dbl		   = 1.1;
	char   some_char	   = ' ';

	printl("Exp: 7 ns Time creation+destruction of unassigned var + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var().assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}

	printl();

	printl("Exp: 15  ns - Creation+destruction of string var '12345.67' + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var("12345.67").assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}
	printl();

	printl("Exp: 65 ns - Conversion of string var '12345.67' to double (Using fast_float::from_chars on Ubuntu 20.04/g++v9.3 and Ubuntu 22.04/g++v11.2)");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			some_dbl = var("12345.67").toDouble();
			//var("12345.67");
		}
		printl("Act:", round((ostime() - started - setup_time) / nn * 1E9), "ns");
	}

	printl();

	printl("Exp: 6 ns - Creation+destruction of double var 12345.67 + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var(12367).assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}
	printl();

	printl("Exp: 650  ns - Conversion of double var 12345.67 to string and return length (Using RYU D2S on Ubuntu 20.04/g++v9.3 and std::to_chars on Ubuntu 22.04/g++v11.2)");
	{
		var nn		= 10'000'000;
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			some_char = var(12345.67).toChar();
		}
		printl("Act:", round((ostime() - started - setup_time) / nn * 1E9), "ns");
	}

	// Test integer loops
	{
		printl();
		printl("Testing simple integer for loops");
		printl("--------------------------------");

		int firstcasen = COMMAND.f(2);
		if (not firstcasen)
			firstcasen = 0;

		int ncases = 20;

		for (int casen = firstcasen; casen <= ncases; casen++) {

			printl();
			for (int repeatn = 0; repeatn < 3; repeatn++) {

				int nn = 100'000'000;

				int i1 = 1;
				//			double d1 = 0;
				//			char c1 = '\0';
				//			char* cp1 = nullptr;
				bool		b1	= true;
				var			v1	= 1;
				std::string ss1 = "x";

				var started = ostime();

				switch (casen) {

					break;
					case 0:
						if (repeatn eq 0)
							printl("Exp: 35     ns - old var method - for (var;;)");
						nn = 10'000'000;
						for (var v2 = 0; v2 <= nn; v2++) {
							i1 = v2;
						};

						break;
					case 1:
						if (repeatn eq 0)
							printl("Exp: 15     ns - new var method - for (var:range)");
						for (const var v2 : range(0 to nn)) {
							i1 = v2;
						};

						break;
					case 2:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - old int method - for (int;;)");
						for (int i2 = 0; i2 <= nn; i2++) {
							i1 = i2;
						};

						break;
					case 3:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - new int method - for (int:range)");
						for (int i2 : range(0 to nn)) {
							i1 = i2;
						};

						break;
					case 4:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - new int method using boost - for (int:range)");
						for (int i2 : boost::irange(0, nn)) {
							i1 = i2;
						};

						break;
					case 5:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct empty var + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var x;
							b1 = x.assigned();
						};

						break;
					case 6:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from int + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var i = 123456;
							b1	  = i.assigned();
						};

						break;
					case 7:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from bool + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var b = true;
							b1	  = b.assigned();
						};

						break;
					case 8:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from double + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var d = 123.456;
							b1	  = d.assigned();
						};

						break;
					case 9:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from cstr + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = "1";
							b1	  = s.assigned();
						};

						break;
					case 10:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from char + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = '1';
							b1	  = s.assigned();
						};

						break;
					case 11:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from std::string + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = ss1;
							b1	  = s.assigned();
						};

						break;
					case 12:
						if (repeatn eq 0)
							printl("Exp: 4.5   ns - pure test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = v1.assigned();
						};

						break;
					case 13:
						if (repeatn eq 0)
							printl("Exp: 0.9   ns - assign from int");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = 123456;
						};

						break;
					case 14:
						if (repeatn eq 0)
							printl("Exp: 0.9   ns - assign from bool");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = true;
						};

						break;
					case 15:
						if (repeatn eq 0)
							printl("Exp: 1.3   ns - assign from double");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = 123.456;
						};

						break;
					case 16:
						if (repeatn eq 0)
							printl("Exp: 13    ns - assign from cstr");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = "1";
						};

						break;
					case 17:
						if (repeatn eq 0)
							printl("Exp: 11    ns - assign from char");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = '1';
						};

						break;
					case 18:
						if (repeatn eq 0)
							printl("Exp: 11    ns - assign from std::string");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = ss1;
						};

						break;
					case 19:
						if (repeatn eq 0)
							printl("Exp: 22    ns - var + int + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = (v1 + i2).assigned();
						};

						break;
					case 20:
						if (repeatn eq 0)
							printl("Exp: 22    ns - var + 0.1 + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = (v1 + 0.1).assigned();
						};
				}
				var ended = ostime();
				if (i1 or b1 or v1)
					printl("Act:", ((ended - started) / int(nn) * 1e9).round(3), "ns");
			}
		}
	}

	// Ensure optimiser doesnt see as unused
	printl(the_truth_hurts, some_dbl, some_char);

	printl();
	printl(elapsedtimetext());
	printl("Test passed");

	return 0;
}

programexit()
<commit_msg>Reduce test_perf loops to avoid timeout when testing in debug mode<commit_after>#undef NDEBUG  //because we are using assert to check actual operations that cannot be skipped in release mode testing
#include <boost/range/irange.hpp>
#include <cassert>

#include <exodus/program.h>
programinit()

	function main() {

	// Quit if running under make since there are no tests
	if (osgetenv("MAKELEVEL")) {
		printl();
		printl("Test passed - skipped because MAKELEVEL is set");
		return 0;
	}

	printl();

	int nn = 1'000'000;
	var setup_time;

	bool   the_truth_hurts = false;
	double some_dbl		   = 1.1;
	char   some_char	   = ' ';

	printl("Exp: 7 ns Time creation+destruction of unassigned var + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var().assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}

	printl();

	printl("Exp: 15  ns - Creation+destruction of string var '12345.67' + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var("12345.67").assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}
	printl();

	printl("Exp: 65 ns - Conversion of string var '12345.67' to double (Using fast_float::from_chars on Ubuntu 20.04/g++v9.3 and Ubuntu 22.04/g++v11.2)");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			some_dbl = var("12345.67").toDouble();
			//var("12345.67");
		}
		printl("Act:", round((ostime() - started - setup_time) / nn * 1E9), "ns");
	}

	printl();

	printl("Exp: 6 ns - Creation+destruction of double var 12345.67 + test within int loop");
	{
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			the_truth_hurts = var(12367).assigned();
		}
		setup_time = ostime() - started;
		printl("Act:", round((setup_time) / nn * 1E9), "ns");
	}
	printl();

	printl("Exp: 650  ns - Conversion of double var 12345.67 to string and return length (Using RYU D2S on Ubuntu 20.04/g++v9.3 and std::to_chars on Ubuntu 22.04/g++v11.2)");
	{
		var nn		= 100'000;
		var started = ostime();
		for (int ii = 0; ii < nn; ii++) {
			some_char = var(12345.67).toChar();
		}
		printl("Act:", round((ostime() - started - setup_time) / nn * 1E9), "ns");
	}

	// Test integer loops
	{
		printl();
		printl("Testing simple integer for loops");
		printl("--------------------------------");

		int firstcasen = COMMAND.f(2);
		if (not firstcasen)
			firstcasen = 0;

		int ncases = 20;

		for (int casen = firstcasen; casen <= ncases; casen++) {

			printl();
			for (int repeatn = 0; repeatn < 3; repeatn++) {

				int nn = 1'000'000;

				int i1 = 1;
				//			double d1 = 0;
				//			char c1 = '\0';
				//			char* cp1 = nullptr;
				bool		b1	= true;
				var			v1	= 1;
				std::string ss1 = "x";

				var started = ostime();

				switch (casen) {

					break;
					case 0:
						if (repeatn eq 0)
							printl("Exp: 35     ns - old var method - for (var;;)");
						nn = 1'000'000;
						for (var v2 = 0; v2 <= nn; v2++) {
							i1 = v2;
						};

						break;
					case 1:
						if (repeatn eq 0)
							printl("Exp: 15     ns - new var method - for (var:range)");
						for (const var v2 : range(0 to nn)) {
							i1 = v2;
						};

						break;
					case 2:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - old int method - for (int;;)");
						for (int i2 = 0; i2 <= nn; i2++) {
							i1 = i2;
						};

						break;
					case 3:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - new int method - for (int:range)");
						for (int i2 : range(0 to nn)) {
							i1 = i2;
						};

						break;
					case 4:
						if (repeatn eq 0)
							printl("Exp: 0.840 ns - new int method using boost - for (int:range)");
						for (int i2 : boost::irange(0, nn)) {
							i1 = i2;
						};

						break;
					case 5:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct empty var + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var x;
							b1 = x.assigned();
						};

						break;
					case 6:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from int + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var i = 123456;
							b1	  = i.assigned();
						};

						break;
					case 7:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from bool + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var b = true;
							b1	  = b.assigned();
						};

						break;
					case 8:
						if (repeatn eq 0)
							printl("Exp: 6.5   ns - construct from double + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var d = 123.456;
							b1	  = d.assigned();
						};

						break;
					case 9:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from cstr + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = "1";
							b1	  = s.assigned();
						};

						break;
					case 10:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from char + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = '1';
							b1	  = s.assigned();
						};

						break;
					case 11:
						if (repeatn eq 0)
							printl("Exp: 12    ns - construct from std::string + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							var s = ss1;
							b1	  = s.assigned();
						};

						break;
					case 12:
						if (repeatn eq 0)
							printl("Exp: 4.5   ns - pure test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = v1.assigned();
						};

						break;
					case 13:
						if (repeatn eq 0)
							printl("Exp: 0.9   ns - assign from int");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = 123456;
						};

						break;
					case 14:
						if (repeatn eq 0)
							printl("Exp: 0.9   ns - assign from bool");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = true;
						};

						break;
					case 15:
						if (repeatn eq 0)
							printl("Exp: 1.3   ns - assign from double");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = 123.456;
						};

						break;
					case 16:
						if (repeatn eq 0)
							printl("Exp: 13    ns - assign from cstr");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = "1";
						};

						break;
					case 17:
						if (repeatn eq 0)
							printl("Exp: 11    ns - assign from char");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = '1';
						};

						break;
					case 18:
						if (repeatn eq 0)
							printl("Exp: 11    ns - assign from std::string");
						for (int i2 = 0; i2 <= nn; i2++) {
							v1 = ss1;
						};

						break;
					case 19:
						if (repeatn eq 0)
							printl("Exp: 22    ns - var + int + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = (v1 + i2).assigned();
						};

						break;
					case 20:
						if (repeatn eq 0)
							printl("Exp: 22    ns - var + 0.1 + test");
						for (int i2 = 0; i2 <= nn; i2++) {
							b1 = (v1 + 0.1).assigned();
						};
				}
				var ended = ostime();
				if (i1 or b1 or v1)
					printl("Act:", ((ended - started) / int(nn) * 1e9).round(3), "ns");
			}
		}
	}

	// Ensure optimiser doesnt see as unused
	printl(the_truth_hurts, some_dbl, some_char);

	printl();
	printl(elapsedtimetext());
	printl("Test passed");

	return 0;
}

programexit()
<|endoftext|>


<commit_before>/*
 // Copyright (c) 2015-2016-2016 Pierre Guillot.
 // For information on usage and redistribution, and for a DISCLAIMER OF ALL
 // WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*/

#include <iostream>
#include "test.hpp"
extern "C"
{
#include "../thread/src/thd.h"
}

#define XPD_TEST_NLOOP  16
#define XPD_TEST_NTHD   4

class instance_tester : private xpd::instance
{
public:
    instance_tester() : m_counter(0ul)
    {
        ;
    }

    ~instance_tester()
    {
        if(m_patch)
        {
            xpd::instance::close(m_patch);
        }
    }

    bool load(std::string const& name)
    {
        if(m_patch)
        {
            xpd::instance::close(m_patch);
        }
        if(m_tto)
        {
            xpd::instance::unbind(m_tto);
        }
        m_patch = xpd::instance::load(name, "");
        if(bool(m_patch))
        {
            char uid[512];
            sprintf(uid, "%i", int(m_patch.unique_id()));
            m_tfrom = std::string(uid) + std::string("-fromxpd");
            m_tto   = std::string(uid) + std::string("-toxpd");
            xpd::instance::bind(m_tto);
            return true;
        }
        return false;
    }

    bool prepare(const int nins, const int nouts, const int samplerate, const int nsamples)
    {
        xpd::instance::prepare(nins, nouts, samplerate, nsamples);
        m_blksize = nsamples;
        return xpd::instance::samplerate() == samplerate;
    }

    void send(std::vector<xpd::atom> const& vec)
    {
        xpd::instance::send(m_tfrom, xpd::symbol("list"), vec);
    }

    void receive(xpd::tie name, xpd::symbol selector, std::vector<xpd::atom> const& atoms) xpd_final
    {
        m_counter++;
    }

    void receive(xpd::console::post const& post) xpd_final
    {
        m_counter++;
    }

    size_t counter() const xpd_noexcept
    {
        return m_counter;
    }

    static void test(instance_tester* inst)
    {
        inst->m_counter = 0ul;
        for(size_t i = 0; i < XPD_TEST_NLOOP; i++)
        {
            inst->perform(inst->m_blksize, 0, NULL, 0, NULL);
        }
    }

private:
    xpd::patch m_patch;
    xpd::tie   m_tfrom;
    xpd::tie   m_tto;
    size_t     m_counter;
    size_t     m_blksize;
};

TEST_CASE("instance", "[instance]")
{
    instance_tester inst[XPD_TEST_NTHD];
    thd_thread      thd[XPD_TEST_NTHD];

    SECTION("post")
    {
        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            REQUIRE(inst[i].load("test_post.pd"));
            REQUIRE(inst[i].prepare(0, 0, 44100, 256));
            thd_thread_detach(thd+i, (thd_thread_method)(&instance_tester::test), inst+i);
        }

        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            thd_thread_join(thd+i);
            CHECK(inst[i].counter() == XPD_TEST_NLOOP);
        }
    }

    SECTION("message")
    {
        std::vector<xpd::atom> vec;
        vec.push_back(1.2f);
        vec.push_back(xpd::symbol("zaza"));
        vec.push_back(xpd::symbol("zozo"));
        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            REQUIRE(inst[i].load("test_message.pd"));
            REQUIRE(inst[i].prepare(0, 0, 44100, 256));
            inst[i].send(vec);
            thd_thread_detach(thd+i, (thd_thread_method)(&instance_tester::test), inst+i);
        }

        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            thd_thread_join(thd+i);
            //CHECK(inst[i].counter() == XPD_TEST_NLOOP);
        }
    }
}

#undef XPD_TEST_NLOOP

<commit_msg>A faire en rentrant à la maison...<commit_after>/*
 // Copyright (c) 2015-2016-2016 Pierre Guillot.
 // For information on usage and redistribution, and for a DISCLAIMER OF ALL
 // WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*/

#include <iostream>
#include "test.hpp"
extern "C"
{
#include "../thread/src/thd.h"
}

#define XPD_TEST_NLOOP  16
#define XPD_TEST_NTHD   4

static xpd::mutex gmutex;

class instance_tester : private xpd::instance
{
public:
    instance_tester() : m_npost(0ul), m_nmess(0ul)
    {
        ;
    }

    ~instance_tester()
    {
        if(m_patch)
        {
            xpd::instance::close(m_patch);
        }
    }

    bool load(std::string const& name)
    {
        if(m_patch)
        {
            xpd::instance::close(m_patch);
        }
        if(m_tto)
        {
            xpd::instance::unbind(m_tto);
        }
        m_patch = xpd::instance::load(name, "");
        if(bool(m_patch))
        {
            char uid[512];
            sprintf(uid, "%i", int(m_patch.unique_id()));
            m_tfrom = std::string(uid) + std::string("-fromxpd");
            m_tto   = std::string(uid) + std::string("-toxpd");
            xpd::instance::bind(m_tto);
            return true;
        }
        return false;
    }

    bool prepare(const int nins, const int nouts, const int samplerate, const int nsamples)
    {
        xpd::instance::prepare(nins, nouts, samplerate, nsamples);
        m_blksize = nsamples;
        return xpd::instance::samplerate() == samplerate;
    }

    void send(std::vector<xpd::atom> const& vec)
    {
        xpd::instance::send(m_tfrom, xpd::symbol("list"), vec);
    }

    void receive(xpd::tie name, xpd::symbol selector, std::vector<xpd::atom> const& atoms) xpd_final
    {
        m_counter++;
    }

    void receive(xpd::console::post const& post) xpd_final
    {
        m_counter++;
    }

    size_t counter() const xpd_noexcept
    {
        return m_counter;
    }

    static void test(instance_tester* inst)
    {
        gmutex.lock();
        for(size_t i = 0; i < XPD_TEST_NLOOP; i++)
        {
            inst->perform(inst->m_blksize, 0, NULL, 0, NULL);
        }
        gmutex.unlock();
    }

private:
    xpd::patch m_patch;
    xpd::tie   m_tfrom;
    xpd::tie   m_tto;
    size_t     m_npost;
    size_t     m_nmess;
    size_t     m_blksize;
};

TEST_CASE("instance", "[instance]")
{
    instance_tester inst[XPD_TEST_NTHD];
    thd_thread      thd[XPD_TEST_NTHD];

    SECTION("post")
    {
        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            REQUIRE(inst[i].load("test_post.pd"));
            REQUIRE(inst[i].prepare(0, 0, 44100, 256));
            thd_thread_detach(thd+i, (thd_thread_method)(&instance_tester::test), inst+i);
        }

        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            thd_thread_join(thd+i);
            CHECK(inst[i].counter() == XPD_TEST_NLOOP);
        }
    }

    SECTION("message")
    {
        std::vector<xpd::atom> vec;
        vec.push_back(1.2f);
        vec.push_back(xpd::symbol("zaza"));
        vec.push_back(xpd::symbol("zozo"));
        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            REQUIRE(inst[i].load("test_message.pd"));
            REQUIRE(inst[i].prepare(0, 0, 44100, 256));
            inst[i].send(vec);
            thd_thread_detach(thd+i, (thd_thread_method)(&instance_tester::test), inst+i);
        }

        for(size_t i = 0; i < XPD_TEST_NTHD; ++i)
        {
            //thd_thread_join(thd+i);
            CHECK(inst[i].counter() == XPD_TEST_NLOOP);
        }
    }
}

#undef XPD_TEST_NLOOP

<|endoftext|>


<commit_before>#include "catch.hpp"
#include "util.h"
#include <shl_exception.h>
#include <tokenizer.h>
#include <grammar_loader.h>

using namespace shl;

TEST_CASE("Tokenizer Tests") {
    Tokenizer tokenizer;
    GrammarLoader loader;

    SECTION("can load grammar and tokenizer string") {
        string data = load_string("fixture/hello.json");
        string source = "hello world!";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );
        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE( tokens[0].second.name() == "source.hello" );

        REQUIRE( tokens[1].first.substr(source) == "hello" );
        REQUIRE( tokens[1].second.name() == "source.hello prefix.hello" );

        REQUIRE( tokens[2].first.substr(source) == "world!" );
        REQUIRE( tokens[2].second.name() == "source.hello suffix.hello" );

        REQUIRE( tokens[3].first.substr(source) == "!" );
        REQUIRE( tokens[3].second.name() == "source.hello suffix.hello emphasis.hello" );
    }

    SECTION("return a single token when matches a single pattern with no capture groups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "return";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 2 );
        REQUIRE( tokens[1].first.substr(source) == "return" );
        REQUIRE( tokens[1].second.name() == "source.coffee keyword.control.coffee" );
    }

    SECTION("return several tokens when matches a single pattern with capture gorups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "new foo.bar.Baz";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );

        REQUIRE( tokens[1].first.substr(source) == source );
        REQUIRE( tokens[1].second.name() == "source.coffee meta.class.instance.constructor" );

        REQUIRE( tokens[2].first.substr(source) == "new" );
        REQUIRE( tokens[2].second.name() == "source.coffee meta.class.instance.constructor keyword.operator.new.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "foo.bar.Baz" );
        REQUIRE( tokens[3].second.name() == "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee" );
    }

    SECTION("return grammar top level token when no match at all") {
        string data = load_string("fixture/text.json");
        string source = "   ";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 1 );

        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE( tokens[0].second.name() == "text.plain" );
    }

    SECTION("will throw when scope is not properly closed (i.e. source code is malformed)") {
        string data = load_string("fixture/c.json");
        string source = "int main() {";
        Grammar g = loader.load(data);

        REQUIRE_THROWS_AS(tokenizer.tokenize(g, source), InvalidSourceException);
    }

    SECTION("will not throw when scope is not properly closed, if OPTION_TOLERATE_ERROR is specified") {
        string data = load_string("fixture/c.json");
        string source = "int main() {";
        Grammar g = loader.load(data);
        Tokenizer tokenizer(Tokenizer::OPTION_TOLERATE_ERROR);

        REQUIRE_NOTHROW(tokenizer.tokenize(g, source));
    }

    SECTION("the enclosing scope will cover the sub-scopes") {
        string data = load_string("fixture/coffee-script.json");
        string source = " return new foo.bar.Baz ";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 5 );
        REQUIRE (tokens[0].first.substr(source) == source );
        REQUIRE (tokens[0].second.name() == "source.coffee" );

        REQUIRE (tokens[1].first.substr(source) == "return" );
        REQUIRE (tokens[1].second.name() == "source.coffee keyword.control.coffee" );

        REQUIRE (tokens[2].first.substr(source) == "new foo.bar.Baz" );
        REQUIRE (tokens[2].second.name() == "source.coffee meta.class.instance.constructor" );

        REQUIRE (tokens[3].first.substr(source) == "new" );
        REQUIRE (tokens[3].second.name() == "source.coffee meta.class.instance.constructor keyword.operator.new.coffee" );

        REQUIRE (tokens[4].first.substr(source) == "foo.bar.Baz" );
        REQUIRE (tokens[4].second.name() == "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee" );
    }

    SECTION("only return matched capture groups when match rule has an optional captre groups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "class Foo";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );

        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE (tokens[0].second.name() == "source.coffee" );

        REQUIRE( tokens[1].first.substr(source) == source );
        REQUIRE (tokens[1].second.name() == "source.coffee meta.class.coffee" );

        REQUIRE( tokens[2].first.substr(source) == "class" );
        REQUIRE (tokens[2].second.name() == "source.coffee meta.class.coffee storage.type.class.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "Foo" );
        REQUIRE (tokens[3].second.name() == "source.coffee meta.class.coffee entity.name.type.class.coffee" );
    }
}
<commit_msg>test when capture beyond matched range, and has enclosed capture groups<commit_after>#include "catch.hpp"
#include "util.h"
#include <shl_exception.h>
#include <tokenizer.h>
#include <grammar_loader.h>

using namespace shl;

TEST_CASE("Tokenizer Tests") {
    Tokenizer tokenizer;
    GrammarLoader loader;

    SECTION("can load grammar and tokenizer string") {
        string data = load_string("fixture/hello.json");
        string source = "hello world!";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );
        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE( tokens[0].second.name() == "source.hello" );

        REQUIRE( tokens[1].first.substr(source) == "hello" );
        REQUIRE( tokens[1].second.name() == "source.hello prefix.hello" );

        REQUIRE( tokens[2].first.substr(source) == "world!" );
        REQUIRE( tokens[2].second.name() == "source.hello suffix.hello" );

        REQUIRE( tokens[3].first.substr(source) == "!" );
        REQUIRE( tokens[3].second.name() == "source.hello suffix.hello emphasis.hello" );
    }

    SECTION("return a single token when matches a single pattern with no capture groups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "return";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 2 );
        REQUIRE( tokens[1].first.substr(source) == "return" );
        REQUIRE( tokens[1].second.name() == "source.coffee keyword.control.coffee" );
    }

    SECTION("return several tokens when matches a single pattern with capture gorups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "new foo.bar.Baz";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );

        REQUIRE( tokens[1].first.substr(source) == source );
        REQUIRE( tokens[1].second.name() == "source.coffee meta.class.instance.constructor" );

        REQUIRE( tokens[2].first.substr(source) == "new" );
        REQUIRE( tokens[2].second.name() == "source.coffee meta.class.instance.constructor keyword.operator.new.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "foo.bar.Baz" );
        REQUIRE( tokens[3].second.name() == "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee" );
    }

    SECTION("return grammar top level token when no match at all") {
        string data = load_string("fixture/text.json");
        string source = "   ";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 1 );

        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE( tokens[0].second.name() == "text.plain" );
    }

    SECTION("will throw when scope is not properly closed (i.e. source code is malformed)") {
        string data = load_string("fixture/c.json");
        string source = "int main() {";
        Grammar g = loader.load(data);

        REQUIRE_THROWS_AS(tokenizer.tokenize(g, source), InvalidSourceException);
    }

    SECTION("will not throw when scope is not properly closed, if OPTION_TOLERATE_ERROR is specified") {
        string data = load_string("fixture/c.json");
        string source = "int main() {";
        Grammar g = loader.load(data);
        Tokenizer tokenizer(Tokenizer::OPTION_TOLERATE_ERROR);

        REQUIRE_NOTHROW(tokenizer.tokenize(g, source));
    }

    SECTION("the enclosing scope will cover the sub-scopes") {
        string data = load_string("fixture/coffee-script.json");
        string source = " return new foo.bar.Baz ";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 5 );
        REQUIRE (tokens[0].first.substr(source) == source );
        REQUIRE (tokens[0].second.name() == "source.coffee" );

        REQUIRE (tokens[1].first.substr(source) == "return" );
        REQUIRE (tokens[1].second.name() == "source.coffee keyword.control.coffee" );

        REQUIRE (tokens[2].first.substr(source) == "new foo.bar.Baz" );
        REQUIRE (tokens[2].second.name() == "source.coffee meta.class.instance.constructor" );

        REQUIRE (tokens[3].first.substr(source) == "new" );
        REQUIRE (tokens[3].second.name() == "source.coffee meta.class.instance.constructor keyword.operator.new.coffee" );

        REQUIRE (tokens[4].first.substr(source) == "foo.bar.Baz" );
        REQUIRE (tokens[4].second.name() == "source.coffee meta.class.instance.constructor entity.name.type.instance.coffee" );
    }

    SECTION("only return matched capture groups when match rule has an optional captre groups") {
        string data = load_string("fixture/coffee-script.json");
        string source = "class Foo";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 4 );

        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE (tokens[0].second.name() == "source.coffee" );

        REQUIRE( tokens[1].first.substr(source) == source );
        REQUIRE (tokens[1].second.name() == "source.coffee meta.class.coffee" );

        REQUIRE( tokens[2].first.substr(source) == "class" );
        REQUIRE (tokens[2].second.name() == "source.coffee meta.class.coffee storage.type.class.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "Foo" );
        REQUIRE (tokens[3].second.name() == "source.coffee meta.class.coffee entity.name.type.class.coffee" );
    }

    /* The tokens are sorted in the way similar to the in-order traversal of the AST
     * This holds true even for begin_captures/end_capture/captures rules, because
     * capture group themselves have hierarchy. Although capture rules are listed in
     * any order, since we simply apply scope to the captured group in ascending order(0,1...N),
     * we are actually apply in the same way of the in-order traversal.
     *
     * e.g. ((()())()), the capture group number are corresponding to below tree
     *             1
     *           /   \
     *          2     5
     *         / \
     *        3   4
     */
    SECTION("when capture ranges overlap, ensure parent rule appears ahead of child") {
        string data = load_string("fixture/coffee-script.json");
        string source = "  destroy: ->";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 6 );

        REQUIRE( tokens[0].first.substr(source) == source );
        REQUIRE(tokens[0].second.name() == "source.coffee" );

        REQUIRE( tokens[1].first.substr(source) == "destroy" );
        REQUIRE (tokens[1].second.name() == "source.coffee meta.function.coffee" );

        REQUIRE( tokens[2].first.substr(source) == "destroy" );
        REQUIRE(tokens[2].second.name() == "source.coffee meta.function.coffee entity.name.function.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "y" );
        REQUIRE(tokens[3].second.name() == "source.coffee meta.function.coffee entity.name.function.coffee entity.name.function.coffee" );

        REQUIRE( tokens[4].first.substr(source) == ":" );
        REQUIRE (tokens[4].second.name() == "source.coffee keyword.operator.coffee" );

        REQUIRE( tokens[5].first.substr(source) == "->" );
        REQUIRE (tokens[5].second.name() == "source.coffee storage.type.function.coffee" );
    }

    SECTION("when capture beyond the matched range (i.e. capture in a look ahead group)") {
        string data = load_string("fixture/coffee-script.json");
        string source = "  destroy: ->";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 6 );

        // the scope "source.coffee meta.function.coffee storage.type.function.coffee" captures
        // "->", which is beyond the matching range. so ignore it.
        REQUIRE_FALSE( tokens[4].first.substr(source) == "->" );
        REQUIRE_FALSE(tokens[4].second.name() == "source.coffee meta.function.coffee storage.type.function.coffee" );
    }

    SECTION("the enclosed capture group will has one additional ScopeName") {
        string data = load_string("fixture/coffee-script.json");
        string source = "  destroy: ->";
        Grammar g = loader.load(data);
        auto tokens = tokenizer.tokenize(g, source);

        REQUIRE( tokens.size() == 6 );

        REQUIRE( tokens[2].first.substr(source) == "destroy" );
        REQUIRE(tokens[2].second.name() == "source.coffee meta.function.coffee entity.name.function.coffee" );

        REQUIRE( tokens[3].first.substr(source) == "y" );
        REQUIRE(tokens[3].second.name() == "source.coffee meta.function.coffee entity.name.function.coffee entity.name.function.coffee" );

    }
}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>

#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>

void print( boost::property_tree::ptree pt, int indent = 0 ){
    for( auto const & element : pt ){
        if( element.first == "name" ){
            auto const xmlAttrs = element.second;
            auto const attrs = xmlAttrs.get_child( "<xmlattr>" );

            auto const elementName = element.first;
            auto const elementValue = xmlAttrs.get_value< std::string >();

            std::cout
                << std::string( indent, ' ' )
                << elementName << " " << elementValue
                << std::endl;

            for( auto const & attr : attrs ){
                auto const attributeName = attr.first;
                auto const attributeValue = attr.second.get_value< std::string >();

                std::cout
                    << std::string( indent + 4, ' ' )
                    << attributeName << ": " << attributeValue
                    << std::endl;
            }
        }
        else{
            print( element.second, indent + 4 );
        }
    }
}

int main(){
    std::ifstream input( "./xml.xml" );

    boost::property_tree::ptree propertyTree;
    read_xml( input, propertyTree );
    print( propertyTree );

    return 0;
}

<commit_msg>boost/xml<commit_after>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 *
 * Compilation:
 *      g++ --std=c++11 xml.cpp -o xml
 *
 * Usage:
 *      $ ./xml
 */

#include <fstream>
#include <iostream>
#include <string>

#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>

void print( boost::property_tree::ptree pt, int indent = 0 ){
    for( auto const & element : pt ){
        if( element.first == "name" ){
            auto const xmlAttrs = element.second;
            auto const attrs = xmlAttrs.get_child( "<xmlattr>" );

            auto const elementName = element.first;
            auto const elementValue = xmlAttrs.get_value< std::string >();

            std::cout
                << std::string( indent, ' ' )
                << elementName << " " << elementValue
                << std::endl;

            for( auto const & attr : attrs ){
                auto const attributeName = attr.first;
                auto const attributeValue = attr.second.get_value< std::string >();

                std::cout
                    << std::string( indent + 4, ' ' )
                    << attributeName << ": " << attributeValue
                    << std::endl;
            }
        }
        else if( element.first == "doc" ){
            std::cout
                << std::string( indent, ' ' )
                << element.first
                << std::endl;
        }

        print( element.second, indent + 4 );
    }
}

int main(){
    std::ifstream input( "./xml.xml" );

    boost::property_tree::ptree propertyTree;
    read_xml( input, propertyTree );
    print( propertyTree );

    return 0;
}

<|endoftext|>