<commit_before>#include <iostream>
#include <fstream>
#include <memory>

#include "HexagonOffload.h"
#include "IRMutator.h"
#include "Substitute.h"
#include "Closure.h"
#include "Param.h"
#include "Image.h"
#include "LLVM_Output.h"
#include "RemoveTrivialForLoops.h"
#include "InjectHostDevBufferCopies.h"
#include "LLVM_Headers.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;

namespace {

// Replace the parameter objects of loads/stores with a new parameter
// object.
class ReplaceParams : public IRMutator {
    const std::map<std::string, Parameter> &replacements;

    using IRMutator::visit;

    void visit(const Load *op) {
        auto i = replacements.find(op->name);
        if (i != replacements.end()) {
            expr = Load::make(op->type, op->name, mutate(op->index), op->image, i->second);
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Store *op) {
        auto i = replacements.find(op->name);
        if (i != replacements.end()) {
            stmt = Store::make(op->name, mutate(op->value), mutate(op->index), i->second);
        } else {
            IRMutator::visit(op);
        }
    }

public:
    ReplaceParams(const std::map<std::string, Parameter> &replacements)
        : replacements(replacements) {}
};

Stmt replace_params(Stmt s, const std::map<std::string, Parameter> &replacements) {
    return ReplaceParams(replacements).mutate(s);
}

class InjectHexagonRpc : public IRMutator {
    std::map<std::string, Expr> state_vars;

    Module device_code;

    /** Alignment info for Int(32) variables in scope, so we don't
     * lose the information when creating Hexagon kernels. */
    Scope<ModulusRemainder> alignment_info;

    Expr state_var(const std::string& name, Type type) {
        Expr& var = state_vars[name];
        if (!var.defined()) {
            Buffer storage(type, {}, nullptr, name + "_buf");
            *(void **)storage.host_ptr() = nullptr;
            var = Load::make(type_of<void*>(), name + "_buf", 0, storage, Parameter());
        }
        return var;
    }

    Expr state_var_ptr(const std::string& name, Type type) {
        Expr var = state_var(name, type);
        return Call::make(Handle(), Call::address_of, {var}, Call::Intrinsic);
    }

    Expr module_state() {
        return state_var("hexagon_module_state", type_of<void*>());
    }

    Expr module_state_ptr() {
        return state_var_ptr("hexagon_module_state", type_of<void*>());
    }

    // Create a Buffer containing the given buffer/size, and return an
    // expression for a pointer to the first element.
    Expr buffer_ptr(const uint8_t* buffer, size_t size, const char* name) {
        Buffer code(type_of<uint8_t>(), {(int)size}, nullptr, name);
        memcpy(code.host_ptr(), buffer, (int)size);

        Expr ptr_0 = Load::make(type_of<uint8_t>(), name, 0, code, Parameter());
        return Call::make(Handle(), Call::address_of, {ptr_0}, Call::Intrinsic);
    }

    using IRMutator::visit;

    void visit(const For *loop) {
        if (loop->device_api == DeviceAPI::Hexagon) {
            // Unrolling or loop partitioning might generate multiple
            // loops with the same name, so we need to make them unique.
            std::string hex_name = unique_name("hex_" + loop->name);

            // After moving this to Hexagon, it doesn't need to be
            // marked Hexagon anymore.
            Stmt body = For::make(loop->name, loop->min, loop->extent, loop->for_type,
                                  DeviceAPI::None, loop->body);
            body = remove_trivial_for_loops(body);

            // Build a closure for the device code.
            // TODO: Should this move the body of the loop to Hexagon,
            // or the loop itself? Currently, this moves the loop itself.
            Closure c(body);

            // Make an argument list, and generate a function in the
            // device_code module. The hexagon runtime code expects
            // the arguments to appear in the order of (input buffers,
            // output buffers, input scalars).  Scalars must be last
            // for the scalar arguments to shadow the symbols of the
            // buffer that get generated by CodeGen_LLVM.
            std::vector<LoweredArgument> input_buffers, output_buffers;
            std::map<std::string, Parameter> replacement_params;
            for (const auto& i : c.buffers) {
                if (i.second.write) {
                    Argument::Kind kind = Argument::OutputBuffer;
                    output_buffers.push_back(LoweredArgument(i.first, kind, i.second.type, i.second.dimensions));
                } else {
                    Argument::Kind kind = Argument::InputBuffer;
                    input_buffers.push_back(LoweredArgument(i.first, kind, i.second.type, i.second.dimensions));
                }

                // Build a parameter to replace.
                Parameter p(i.second.type, true, i.second.dimensions);
                // Assert that buffers are aligned to one HVX vector.
                const int alignment = 128;
                p.set_host_alignment(alignment);
                // The other parameter constraints are already
                // accounted for by the closure grabbing those
                // arguments, so we only need to provide the host
                // alignment.
                replacement_params[i.first] = p;

                // Add an assert to the body that validates the
                // alignment of the buffer.
                if (!device_code.target().has_feature(Target::NoAsserts)) {
                    Expr host_ptr = reinterpret<uint64_t>(Variable::make(Handle(), i.first + ".host"));
                    Expr error = Call::make(Int(32), "halide_error_unaligned_host_ptr",
                                            {i.first, alignment}, Call::Extern);
                    body = Block::make(AssertStmt::make(host_ptr % alignment == 0, error), body);
                }
            }
            body = replace_params(body, replacement_params);

            std::vector<LoweredArgument> args;
            args.insert(args.end(), input_buffers.begin(), input_buffers.end());
            args.insert(args.end(), output_buffers.begin(), output_buffers.end());
            for (const auto& i : c.vars) {
                LoweredArgument arg(i.first, Argument::InputScalar, i.second, 0);
                if (alignment_info.contains(i.first)) {
                    arg.alignment = alignment_info.get(i.first);
                }
                args.push_back(arg);
            }
            device_code.append(LoweredFunc(hex_name, args, body, LoweredFunc::External));

            // Generate a call to hexagon_device_run.
            std::vector<Expr> arg_sizes;
            std::vector<Expr> arg_ptrs;
            std::vector<Expr> arg_flags;

            for (const auto& i : c.buffers) {
                arg_sizes.push_back(Expr((uint64_t) sizeof(buffer_t*)));
                arg_ptrs.push_back(Variable::make(type_of<buffer_t *>(), i.first + ".buffer"));
                // In the flags parameter, bit 0 set indicates the
                // buffer is read, bit 1 set indicates the buffer is
                // written. If neither are set, the argument is a scalar.
                int flags = 0;
                if (i.second.read) flags |= 0x1;
                if (i.second.write) flags |= 0x2;
                arg_flags.push_back(flags);
            }
            for (const auto& i : c.vars) {
                Expr arg = Variable::make(i.second, i.first);
                Expr arg_ptr = Call::make(type_of<void *>(), Call::make_struct, {arg}, Call::Intrinsic);

                // sizeof(scalar-type) will always fit into int32
                arg_sizes.push_back(Expr((uint64_t) i.second.bytes()));
                arg_ptrs.push_back(arg_ptr);
                arg_flags.push_back(0x0);
            }

            // The argument list is terminated with an argument of size 0.
            arg_sizes.push_back(Expr((uint64_t) 0));

            std::string pipeline_name = hex_name + "_argv";
            std::vector<Expr> params;
            params.push_back(module_state());
            params.push_back(pipeline_name);
            params.push_back(state_var_ptr(hex_name, type_of<int>()));
            params.push_back(Call::make(type_of<size_t*>(), Call::make_struct, arg_sizes, Call::Intrinsic));
            params.push_back(Call::make(type_of<void**>(), Call::make_struct, arg_ptrs, Call::Intrinsic));
            params.push_back(Call::make(type_of<int*>(), Call::make_struct, arg_flags, Call::Intrinsic));

            stmt = call_extern_and_assert("halide_hexagon_run", params);

        } else {
            IRMutator::visit(loop);
        }
    }

    void visit(const Let *op) {
        if (op->value.type() == Int(32)) {
            alignment_info.push(op->name, modulus_remainder(op->value, alignment_info));
        }

        IRMutator::visit(op);

        if (op->value.type() == Int(32)) {
            alignment_info.pop(op->name);
        }
    }

    void visit(const LetStmt *op) {
        if (op->value.type() == Int(32)) {
            alignment_info.push(op->name, modulus_remainder(op->value, alignment_info));
        }

        IRMutator::visit(op);

        if (op->value.type() == Int(32)) {
            alignment_info.pop(op->name);
        }
    }

public:
    InjectHexagonRpc(const Target &target) : device_code("hexagon", target) {}

    Stmt inject(Stmt s) {
        s = mutate(s);

        // Skip if there are no device kernels.
        if (device_code.functions().empty()) {
            return s;
        }

        // Compile the device code.
        // TODO: Currently, this requires shelling out to
        // hexagon-clang from the Qualcomm Hexagon SDK, because the
        // Hexagon LLVM target is not fully open source yet. When the
        // LLVM Hexagon target is fully open sourced, we can instead
        // just compile the module to an object, and find a way to
        // link it to a shared object.
        debug(1) << "Hexagon device code module: " << device_code << "\n";

        // First compile the module to an llvm module
        llvm::LLVMContext context;
        std::unique_ptr<llvm::Module> llvm_module =
            compile_module_to_llvm_module(device_code, context);

        #if LLVM_VERSION >= 39
        // Then mess with it, to fix up version differences between
        // our LLVM and hexagon-clang. Yuck.
        for (auto &gv : llvm_module->globals()) {
            // hexagon-clang doesn't understand the local_unnamed_addr
            // attribute, so we must strip it.
            gv.setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
        }
        for (auto &fn : llvm_module->functions()) {
            fn.setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
        }
        #endif

        // Dump the llvm module to a temp file as .ll
        TemporaryFile tmp_bitcode("hex", ".ll");
        TemporaryFile tmp_shared_object("hex", ".so");
        std::unique_ptr<llvm::raw_fd_ostream> ostream =
            make_raw_fd_ostream(tmp_bitcode.pathname());
        compile_llvm_module_to_llvm_assembly(*llvm_module, *ostream);
        ostream->flush();

        // Shell out to hexagon clang to compile it.
        string hex_command;

        const char *path = getenv("HL_HEXAGON_CLANG");
        if (path && path[0]) {
            hex_command = path;
        } else {
            path = getenv("HL_HEXAGON_TOOLS");
            if (path && path[0]) {
                hex_command = string(path) + "/bin/hexagon-clang";
            } else {
                user_error << "Unable to find hexagon-clang: neither HL_HEXAGON_CLANG nor HL_HEXAGON_TOOLS are set properly.";
            }
        }

        hex_command += " ";
        hex_command += tmp_bitcode.pathname();
        hex_command += " -fPIC -O3 -Wno-override-module -shared ";
        if (device_code.target().has_feature(Target::HVX_v62)) {
            hex_command += " -mv62";
        }
        if (device_code.target().has_feature(Target::HVX_128)) {
            hex_command += " -mhvx-double";
        }
        hex_command += " -o " + tmp_shared_object.pathname();
        int result = system(hex_command.c_str());
        internal_assert(result == 0) << "hexagon-clang failed\n";

        // Read the compiled object back in and put it in a buffer in the module
        std::ifstream so(tmp_shared_object.pathname(), std::ios::binary | std::ios::ate);
        internal_assert(so.good()) << "failed to open temporary shared object.";
        std::vector<uint8_t> object(so.tellg());
        so.seekg(0, std::ios::beg);
        so.read(reinterpret_cast<char*>(&object[0]), object.size());

        size_t code_size = object.size();
        Expr code_ptr = buffer_ptr(&object[0], code_size, "hexagon_code");

        // Wrap the statement in calls to halide_initialize_kernels.
        Stmt init_kernels = call_extern_and_assert("halide_hexagon_initialize_kernels",
                                                   {module_state_ptr(), code_ptr, Expr((uint64_t) code_size)});
        s = Block::make(init_kernels, s);

        return s;
    }
};

}

Stmt inject_hexagon_rpc(Stmt s, const Target &host_target) {
    // Make a new target for the device module.
    Target target(Target::NoOS, Target::Hexagon, 32);

    // These feature flags are propagated from the host target to the
    // device module.
    //
    // TODO: We'd like Target::Debug to be in this list too, but trunk
    // llvm currently disagrees with hexagon clang as to what
    // constitutes valid debug info.
    static const Target::Feature shared_features[] = {
        Target::NoAsserts,
        Target::HVX_64,
        Target::HVX_128,
        Target::HVX_v62
    };
    for (Target::Feature i : shared_features) {
        if (host_target.has_feature(i)) {
            target = target.with_feature(i);
        }
    }

    InjectHexagonRpc injector(target);
    s = injector.inject(s);
    return s;
}

}  // namespace Internal
}  // namespace Halide
<commit_msg>Set LSR complexity limit back to the LLVM default<commit_after>#include <iostream>
#include <fstream>
#include <memory>

#include "HexagonOffload.h"
#include "IRMutator.h"
#include "Substitute.h"
#include "Closure.h"
#include "Param.h"
#include "Image.h"
#include "LLVM_Output.h"
#include "RemoveTrivialForLoops.h"
#include "InjectHostDevBufferCopies.h"
#include "LLVM_Headers.h"

namespace Halide {
namespace Internal {

using std::string;
using std::vector;

namespace {

// Replace the parameter objects of loads/stores with a new parameter
// object.
class ReplaceParams : public IRMutator {
    const std::map<std::string, Parameter> &replacements;

    using IRMutator::visit;

    void visit(const Load *op) {
        auto i = replacements.find(op->name);
        if (i != replacements.end()) {
            expr = Load::make(op->type, op->name, mutate(op->index), op->image, i->second);
        } else {
            IRMutator::visit(op);
        }
    }

    void visit(const Store *op) {
        auto i = replacements.find(op->name);
        if (i != replacements.end()) {
            stmt = Store::make(op->name, mutate(op->value), mutate(op->index), i->second);
        } else {
            IRMutator::visit(op);
        }
    }

public:
    ReplaceParams(const std::map<std::string, Parameter> &replacements)
        : replacements(replacements) {}
};

Stmt replace_params(Stmt s, const std::map<std::string, Parameter> &replacements) {
    return ReplaceParams(replacements).mutate(s);
}

class InjectHexagonRpc : public IRMutator {
    std::map<std::string, Expr> state_vars;

    Module device_code;

    /** Alignment info for Int(32) variables in scope, so we don't
     * lose the information when creating Hexagon kernels. */
    Scope<ModulusRemainder> alignment_info;

    Expr state_var(const std::string& name, Type type) {
        Expr& var = state_vars[name];
        if (!var.defined()) {
            Buffer storage(type, {}, nullptr, name + "_buf");
            *(void **)storage.host_ptr() = nullptr;
            var = Load::make(type_of<void*>(), name + "_buf", 0, storage, Parameter());
        }
        return var;
    }

    Expr state_var_ptr(const std::string& name, Type type) {
        Expr var = state_var(name, type);
        return Call::make(Handle(), Call::address_of, {var}, Call::Intrinsic);
    }

    Expr module_state() {
        return state_var("hexagon_module_state", type_of<void*>());
    }

    Expr module_state_ptr() {
        return state_var_ptr("hexagon_module_state", type_of<void*>());
    }

    // Create a Buffer containing the given buffer/size, and return an
    // expression for a pointer to the first element.
    Expr buffer_ptr(const uint8_t* buffer, size_t size, const char* name) {
        Buffer code(type_of<uint8_t>(), {(int)size}, nullptr, name);
        memcpy(code.host_ptr(), buffer, (int)size);

        Expr ptr_0 = Load::make(type_of<uint8_t>(), name, 0, code, Parameter());
        return Call::make(Handle(), Call::address_of, {ptr_0}, Call::Intrinsic);
    }

    using IRMutator::visit;

    void visit(const For *loop) {
        if (loop->device_api == DeviceAPI::Hexagon) {
            // Unrolling or loop partitioning might generate multiple
            // loops with the same name, so we need to make them unique.
            std::string hex_name = unique_name("hex_" + loop->name);

            // After moving this to Hexagon, it doesn't need to be
            // marked Hexagon anymore.
            Stmt body = For::make(loop->name, loop->min, loop->extent, loop->for_type,
                                  DeviceAPI::None, loop->body);
            body = remove_trivial_for_loops(body);

            // Build a closure for the device code.
            // TODO: Should this move the body of the loop to Hexagon,
            // or the loop itself? Currently, this moves the loop itself.
            Closure c(body);

            // Make an argument list, and generate a function in the
            // device_code module. The hexagon runtime code expects
            // the arguments to appear in the order of (input buffers,
            // output buffers, input scalars).  Scalars must be last
            // for the scalar arguments to shadow the symbols of the
            // buffer that get generated by CodeGen_LLVM.
            std::vector<LoweredArgument> input_buffers, output_buffers;
            std::map<std::string, Parameter> replacement_params;
            for (const auto& i : c.buffers) {
                if (i.second.write) {
                    Argument::Kind kind = Argument::OutputBuffer;
                    output_buffers.push_back(LoweredArgument(i.first, kind, i.second.type, i.second.dimensions));
                } else {
                    Argument::Kind kind = Argument::InputBuffer;
                    input_buffers.push_back(LoweredArgument(i.first, kind, i.second.type, i.second.dimensions));
                }

                // Build a parameter to replace.
                Parameter p(i.second.type, true, i.second.dimensions);
                // Assert that buffers are aligned to one HVX vector.
                const int alignment = 128;
                p.set_host_alignment(alignment);
                // The other parameter constraints are already
                // accounted for by the closure grabbing those
                // arguments, so we only need to provide the host
                // alignment.
                replacement_params[i.first] = p;

                // Add an assert to the body that validates the
                // alignment of the buffer.
                if (!device_code.target().has_feature(Target::NoAsserts)) {
                    Expr host_ptr = reinterpret<uint64_t>(Variable::make(Handle(), i.first + ".host"));
                    Expr error = Call::make(Int(32), "halide_error_unaligned_host_ptr",
                                            {i.first, alignment}, Call::Extern);
                    body = Block::make(AssertStmt::make(host_ptr % alignment == 0, error), body);
                }
            }
            body = replace_params(body, replacement_params);

            std::vector<LoweredArgument> args;
            args.insert(args.end(), input_buffers.begin(), input_buffers.end());
            args.insert(args.end(), output_buffers.begin(), output_buffers.end());
            for (const auto& i : c.vars) {
                LoweredArgument arg(i.first, Argument::InputScalar, i.second, 0);
                if (alignment_info.contains(i.first)) {
                    arg.alignment = alignment_info.get(i.first);
                }
                args.push_back(arg);
            }
            device_code.append(LoweredFunc(hex_name, args, body, LoweredFunc::External));

            // Generate a call to hexagon_device_run.
            std::vector<Expr> arg_sizes;
            std::vector<Expr> arg_ptrs;
            std::vector<Expr> arg_flags;

            for (const auto& i : c.buffers) {
                arg_sizes.push_back(Expr((uint64_t) sizeof(buffer_t*)));
                arg_ptrs.push_back(Variable::make(type_of<buffer_t *>(), i.first + ".buffer"));
                // In the flags parameter, bit 0 set indicates the
                // buffer is read, bit 1 set indicates the buffer is
                // written. If neither are set, the argument is a scalar.
                int flags = 0;
                if (i.second.read) flags |= 0x1;
                if (i.second.write) flags |= 0x2;
                arg_flags.push_back(flags);
            }
            for (const auto& i : c.vars) {
                Expr arg = Variable::make(i.second, i.first);
                Expr arg_ptr = Call::make(type_of<void *>(), Call::make_struct, {arg}, Call::Intrinsic);

                // sizeof(scalar-type) will always fit into int32
                arg_sizes.push_back(Expr((uint64_t) i.second.bytes()));
                arg_ptrs.push_back(arg_ptr);
                arg_flags.push_back(0x0);
            }

            // The argument list is terminated with an argument of size 0.
            arg_sizes.push_back(Expr((uint64_t) 0));

            std::string pipeline_name = hex_name + "_argv";
            std::vector<Expr> params;
            params.push_back(module_state());
            params.push_back(pipeline_name);
            params.push_back(state_var_ptr(hex_name, type_of<int>()));
            params.push_back(Call::make(type_of<size_t*>(), Call::make_struct, arg_sizes, Call::Intrinsic));
            params.push_back(Call::make(type_of<void**>(), Call::make_struct, arg_ptrs, Call::Intrinsic));
            params.push_back(Call::make(type_of<int*>(), Call::make_struct, arg_flags, Call::Intrinsic));

            stmt = call_extern_and_assert("halide_hexagon_run", params);

        } else {
            IRMutator::visit(loop);
        }
    }

    void visit(const Let *op) {
        if (op->value.type() == Int(32)) {
            alignment_info.push(op->name, modulus_remainder(op->value, alignment_info));
        }

        IRMutator::visit(op);

        if (op->value.type() == Int(32)) {
            alignment_info.pop(op->name);
        }
    }

    void visit(const LetStmt *op) {
        if (op->value.type() == Int(32)) {
            alignment_info.push(op->name, modulus_remainder(op->value, alignment_info));
        }

        IRMutator::visit(op);

        if (op->value.type() == Int(32)) {
            alignment_info.pop(op->name);
        }
    }

public:
    InjectHexagonRpc(const Target &target) : device_code("hexagon", target) {}

    Stmt inject(Stmt s) {
        s = mutate(s);

        // Skip if there are no device kernels.
        if (device_code.functions().empty()) {
            return s;
        }

        // Compile the device code.
        // TODO: Currently, this requires shelling out to
        // hexagon-clang from the Qualcomm Hexagon SDK, because the
        // Hexagon LLVM target is not fully open source yet. When the
        // LLVM Hexagon target is fully open sourced, we can instead
        // just compile the module to an object, and find a way to
        // link it to a shared object.
        debug(1) << "Hexagon device code module: " << device_code << "\n";

        // First compile the module to an llvm module
        llvm::LLVMContext context;
        std::unique_ptr<llvm::Module> llvm_module =
            compile_module_to_llvm_module(device_code, context);

        #if LLVM_VERSION >= 39
        // Then mess with it, to fix up version differences between
        // our LLVM and hexagon-clang. Yuck.
        for (auto &gv : llvm_module->globals()) {
            // hexagon-clang doesn't understand the local_unnamed_addr
            // attribute, so we must strip it.
            gv.setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
        }
        for (auto &fn : llvm_module->functions()) {
            fn.setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
        }
        #endif

        // Dump the llvm module to a temp file as .ll
        TemporaryFile tmp_bitcode("hex", ".ll");
        TemporaryFile tmp_shared_object("hex", ".so");
        std::unique_ptr<llvm::raw_fd_ostream> ostream =
            make_raw_fd_ostream(tmp_bitcode.pathname());
        compile_llvm_module_to_llvm_assembly(*llvm_module, *ostream);
        ostream->flush();

        // Shell out to hexagon clang to compile it.
        string hex_command;

        const char *path = getenv("HL_HEXAGON_CLANG");
        if (path && path[0]) {
            hex_command = path;
        } else {
            path = getenv("HL_HEXAGON_TOOLS");
            if (path && path[0]) {
                hex_command = string(path) + "/bin/hexagon-clang";
            } else {
                user_error << "Unable to find hexagon-clang: neither HL_HEXAGON_CLANG nor HL_HEXAGON_TOOLS are set properly.";
            }
        }

        hex_command += " ";
        hex_command += tmp_bitcode.pathname();
        hex_command += " -fPIC -O3 -mllvm -lsr-complexity-limit=65535 -Wno-override-module -shared ";
        if (device_code.target().has_feature(Target::HVX_v62)) {
            hex_command += " -mv62";
        }
        if (device_code.target().has_feature(Target::HVX_128)) {
            hex_command += " -mhvx-double";
        }
        hex_command += " -o " + tmp_shared_object.pathname();
        int result = system(hex_command.c_str());
        internal_assert(result == 0) << "hexagon-clang failed\n";

        // Read the compiled object back in and put it in a buffer in the module
        std::ifstream so(tmp_shared_object.pathname(), std::ios::binary | std::ios::ate);
        internal_assert(so.good()) << "failed to open temporary shared object.";
        std::vector<uint8_t> object(so.tellg());
        so.seekg(0, std::ios::beg);
        so.read(reinterpret_cast<char*>(&object[0]), object.size());

        size_t code_size = object.size();
        Expr code_ptr = buffer_ptr(&object[0], code_size, "hexagon_code");

        // Wrap the statement in calls to halide_initialize_kernels.
        Stmt init_kernels = call_extern_and_assert("halide_hexagon_initialize_kernels",
                                                   {module_state_ptr(), code_ptr, Expr((uint64_t) code_size)});
        s = Block::make(init_kernels, s);

        return s;
    }
};

}

Stmt inject_hexagon_rpc(Stmt s, const Target &host_target) {
    // Make a new target for the device module.
    Target target(Target::NoOS, Target::Hexagon, 32);

    // These feature flags are propagated from the host target to the
    // device module.
    //
    // TODO: We'd like Target::Debug to be in this list too, but trunk
    // llvm currently disagrees with hexagon clang as to what
    // constitutes valid debug info.
    static const Target::Feature shared_features[] = {
        Target::NoAsserts,
        Target::HVX_64,
        Target::HVX_128,
        Target::HVX_v62
    };
    for (Target::Feature i : shared_features) {
        if (host_target.has_feature(i)) {
            target = target.with_feature(i);
        }
    }

    InjectHexagonRpc injector(target);
    s = injector.inject(s);
    return s;
}

}  // namespace Internal
}  // namespace Halide
<|endoftext|>


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

#include "TestUtil.h"
#include "MockCluster.h"
#include "RawMetrics.h"
#include "ServerMetrics.h"
#include "RamCloud.h"
#include "IndexKey.h"
#include "IndexLookup.h"

namespace RAMCloud {
// This class provides tablet map and indexlet map info to ObjectFinder.
class IndexLookupRpcRefresher : public ObjectFinder::TableConfigFetcher {
  public:
    IndexLookupRpcRefresher() : called(0) {}
    void getTableConfig(uint64_t tableId,
                        std::map<TabletKey, TabletWithLocator>* tableMap,
                        std::multimap<std::pair<uint64_t, uint8_t>,
                                      ObjectFinder::Indexlet>* tableIndexMap) {

        called++;
        char buffer[100];
        uint64_t numTablets = 10;
        uint8_t numIndexlets = 26;

        tableMap->clear();
        uint64_t tabletRange = 1 + ~0UL / numTablets;
        for (uint64_t i = 0; i < numTablets; i++) {
            uint64_t startKeyHash = i * tabletRange;
            uint64_t endKeyHash = startKeyHash + tabletRange - 1;
            snprintf(buffer, sizeof(buffer), "mock:dataserver=%lu", i);
            if (i == (numTablets - 1))
                endKeyHash = ~0UL;
            Tablet rawEntry({10, startKeyHash, endKeyHash, ServerId(),
                            Tablet::NORMAL, LogPosition()});
            TabletWithLocator entry(rawEntry, buffer);

            TabletKey key {entry.tablet.tableId, entry.tablet.startKeyHash};
            tableMap->insert(std::make_pair(key, entry));
        }

        tableIndexMap->clear();
        for (uint8_t i = 0; i < numIndexlets; i++) {
            auto id = std::make_pair(10, 1); // Pair of table id and index id.
            char firstKey = static_cast<char>('a'+i);
            char firstNotOwnedKey = static_cast<char>('b'+i);
            snprintf(buffer, sizeof(buffer), "mock:indexserver=%u", i);
            ObjectFinder::Indexlet indexlet(
                reinterpret_cast<void *>(&firstKey), 1,
                reinterpret_cast<void *>(&firstNotOwnedKey), 1,
                ServerId(), buffer);
            tableIndexMap->insert(std::make_pair(id, indexlet));
        }
    }
    uint32_t called;
};

class IndexLookupTest : public ::testing::Test {
  public:
    TestLog::Enable logEnabler;
    Tub<RamCloud> ramcloud;
    Context context;
    MockCluster cluster;
    IndexletManager* im;
    Tub<MockTransport> transport;
    IndexKey::IndexKeyRange azKeyRange;

    IndexLookupTest()
        : logEnabler()
        , ramcloud()
        , context()
        , cluster(&context)
        , im()
        , transport()
        , azKeyRange(1, "a", 1, "z", 1)
    {
        Logger::get().setLogLevels(RAMCloud::SILENT_LOG_LEVEL);

        ServerConfig config = ServerConfig::forTesting();
        config.services = {WireFormat::MASTER_SERVICE,
                           WireFormat::PING_SERVICE};
        config.localLocator = "mock:host=master1";
        cluster.addServer(config);

        config.services = {WireFormat::PING_SERVICE};
        config.localLocator = "mock:host=ping1";
        cluster.addServer(config);

        im = &cluster.contexts[0]->getMasterService()->indexletManager;
        ramcloud.construct("mock:");
        transport.construct(ramcloud->clientContext);

        ramcloud->clientContext->objectFinder->tableConfigFetcher.reset(
                new IndexLookupRpcRefresher);
        ramcloud->clientContext->transportManager->registerMock(
                transport.get());

    }

    ~IndexLookupTest()
    {
    }

    DISALLOW_COPY_AND_ASSIGN(IndexLookupTest);
};

TEST_F(IndexLookupTest, construction) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    EXPECT_EQ("mock:indexserver=0",
        indexLookup.lookupRpc.rpc->session->getServiceLocator());
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
}

// Rule 1:
// Handle the completion of a lookIndexKeys RPC.
TEST_F(IndexLookupTest, isReady_lookupComplete) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    const char *nextKey = "next key for rpc";
    size_t nextKeyLen = strlen(nextKey) + 1; // include null char

    Buffer *respBuffer = indexLookup.lookupRpc.rpc->response;

    respBuffer->emplaceAppend<WireFormat::ResponseCommon>()->status = STATUS_OK;
    // numHashes
    respBuffer->emplaceAppend<uint32_t>(10);
    // nextKeyLength
    respBuffer->emplaceAppend<uint16_t>(uint16_t(nextKeyLen));
    // nextKeyHash
    respBuffer->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        respBuffer->emplaceAppend<KeyHash>(i);
    }
    respBuffer->appendCopy(nextKey, (uint32_t) nextKeyLen);

    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(10U, indexLookup.lookupRpc.numHashes + indexLookup.numInserted);
    EXPECT_EQ(0U, indexLookup.nextKeyHash);
    EXPECT_EQ(0, strcmp(reinterpret_cast<char*>(indexLookup.nextKey), nextKey));
}

// Rule 2:
// Copy PKHashes from response buffer of lookup RPC into activeHashes
TEST_F(IndexLookupTest, isReady_activeHashes) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
        WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::FREE, indexLookup.lookupRpc.status);
    for (KeyHash i = 0; i < 10; i++) {
        EXPECT_EQ(i, indexLookup.activeHashes[i]);
    }
}

// Rule 3(a):
// Issue next lookup RPC if an RESULT_READY lookupIndexKeys RPC
// has no unread RPC
TEST_F(IndexLookupTest, isReady_issueNextLookup) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
            WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(1));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->response->emplaceAppend<char>('b');
    EXPECT_EQ("mock:indexserver=0",
                indexLookup.lookupRpc.rpc->session->getServiceLocator());
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    EXPECT_EQ("mock:indexserver=1",
            indexLookup.lookupRpc.rpc->session->getServiceLocator());
}

// Rule 3(b):
// If all lookup RPCs have completed, mark finishedLookup as true, which
// indicates no outgoing lookup RPC thereafter.
TEST_F(IndexLookupTest, isReady_allLookupCompleted) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
            WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::FREE, indexLookup.lookupRpc.status);
    EXPECT_TRUE(indexLookup.finishedLookup);
}

// Rule 5:
// Try to assign the current key hash to an existing RPC to the same server.
TEST_F(IndexLookupTest, isReady_assignPKHashesToSameServer) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
        WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ("mock:dataserver=0",
               indexLookup.readRpcs[0].rpc->session->getServiceLocator());
    EXPECT_EQ(10U, indexLookup.readRpcs[0].numHashes);
    EXPECT_EQ(9U, indexLookup.readRpcs[0].maxPos);
    EXPECT_EQ(IndexLookup::SENT, indexLookup.readRpcs[0].status);
}

// Adds bogus index entries for an object that shouldn't be in range query.
TEST_F(IndexLookupTest, getNext_filtering) {
    ramcloud.construct(&context, "mock:host=coordinator");
    uint64_t tableId = ramcloud->createTable("table");
    ramcloud->createIndex(tableId, 1, 0);

    uint8_t numKeys = 2;

    KeyInfo keyList1[2];
    keyList1[0].keyLength = 11;
    keyList1[0].key = "primaryKey1";
    keyList1[1].keyLength = 1;
    keyList1[1].key = "a";

    KeyInfo keyList2[2];
    keyList2[0].keyLength = 11;
    keyList2[0].key = "primaryKey2";
    keyList2[1].keyLength = 1;
    keyList2[1].key = "b";

    KeyInfo keyList3[2];
    keyList3[0].keyLength = 11;
    keyList3[0].key = "primaryKey3";
    keyList3[1].keyLength = 1;
    keyList3[1].key = "c";

    ramcloud->write(tableId, numKeys, keyList1, "value1");
    ramcloud->write(tableId, numKeys, keyList2, "value2");
    ramcloud->write(tableId, numKeys, keyList3, "value3");

    Key primaryKey1(tableId, keyList1[0].key, keyList1[0].keyLength);
    uint64_t pkhash = primaryKey1.getHash();
    // insert extra entries for pkhash A that would land in search range
    im->insertEntry(tableId, 1, "B2", 2, pkhash);
    im->insertEntry(tableId, 1, "C7", 2, pkhash);

    IndexKey::IndexKeyRange keyRange(1, "B", 1, "D", 1);
    IndexLookup indexLookup(ramcloud.get(), tableId, keyRange);

    uint32_t itemsReturned = 0;
    while (indexLookup.getNext()) {
        itemsReturned++;
    }
    EXPECT_EQ(0U, itemsReturned);

    // insert extra entries for pkhash A that would land in search range
    im->insertEntry(tableId, 1, "b2", 2, 81);
    im->insertEntry(tableId, 1, "c7", 2, pkhash);

    IndexKey::IndexKeyRange keyRange2(1, "b", 1, "d", 1);
    IndexLookup indexLookup2(ramcloud.get(), tableId, keyRange2);

    EXPECT_TRUE(indexLookup2.getNext());
    EXPECT_STREQ("primaryKey2",
        std::string(static_cast<const char*>(
                        indexLookup2.currentObject()->getKey()),
                    indexLookup2.currentObject()->getKeyLength(0)).c_str());

    EXPECT_TRUE(indexLookup2.getNext());
    EXPECT_STREQ("primaryKey3",
        std::string(static_cast<const char*>(
                        indexLookup2.currentObject()->getKey()),
                    indexLookup2.currentObject()->getKeyLength(0)).c_str());

    EXPECT_FALSE(indexLookup2.getNext());
}
} // namespace ramcloud
<commit_msg>Improve test for getNext in IndexLookupTest.<commit_after>/* Copyright (c) 2014-2015 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "TestUtil.h"
#include "IndexKey.h"
#include "IndexLookup.h"
#include "MockCluster.h"
#include "RamCloud.h"
#include "RawMetrics.h"
#include "ServerMetrics.h"
#include "StringUtil.h"

namespace RAMCloud {
// This class provides tablet map and indexlet map info to ObjectFinder.
class IndexLookupRpcRefresher : public ObjectFinder::TableConfigFetcher {
  public:
    IndexLookupRpcRefresher() : called(0) {}
    void getTableConfig(uint64_t tableId,
                        std::map<TabletKey, TabletWithLocator>* tableMap,
                        std::multimap<std::pair<uint64_t, uint8_t>,
                                      ObjectFinder::Indexlet>* tableIndexMap) {

        called++;
        char buffer[100];
        uint64_t numTablets = 10;
        uint8_t numIndexlets = 26;

        tableMap->clear();
        uint64_t tabletRange = 1 + ~0UL / numTablets;
        for (uint64_t i = 0; i < numTablets; i++) {
            uint64_t startKeyHash = i * tabletRange;
            uint64_t endKeyHash = startKeyHash + tabletRange - 1;
            snprintf(buffer, sizeof(buffer), "mock:dataserver=%lu", i);
            if (i == (numTablets - 1))
                endKeyHash = ~0UL;
            Tablet rawEntry({10, startKeyHash, endKeyHash, ServerId(),
                            Tablet::NORMAL, LogPosition()});
            TabletWithLocator entry(rawEntry, buffer);

            TabletKey key {entry.tablet.tableId, entry.tablet.startKeyHash};
            tableMap->insert(std::make_pair(key, entry));
        }

        tableIndexMap->clear();
        for (uint8_t i = 0; i < numIndexlets; i++) {
            auto id = std::make_pair(10, 1); // Pair of table id and index id.
            char firstKey = static_cast<char>('a'+i);
            char firstNotOwnedKey = static_cast<char>('b'+i);
            snprintf(buffer, sizeof(buffer), "mock:indexserver=%u", i);
            ObjectFinder::Indexlet indexlet(
                reinterpret_cast<void *>(&firstKey), 1,
                reinterpret_cast<void *>(&firstNotOwnedKey), 1,
                ServerId(), buffer);
            tableIndexMap->insert(std::make_pair(id, indexlet));
        }
    }
    uint32_t called;
};

class IndexLookupTest : public ::testing::Test {
  public:
    TestLog::Enable logEnabler;
    Tub<RamCloud> ramcloud;
    Context context;
    MockCluster cluster;
    IndexletManager* im;
    Tub<MockTransport> transport;
    IndexKey::IndexKeyRange azKeyRange;

    IndexLookupTest()
        : logEnabler()
        , ramcloud()
        , context()
        , cluster(&context)
        , im()
        , transport()
        , azKeyRange(1, "a", 1, "z", 1)
    {
        Logger::get().setLogLevels(RAMCloud::SILENT_LOG_LEVEL);

        ServerConfig config = ServerConfig::forTesting();
        config.services = {WireFormat::MASTER_SERVICE,
                           WireFormat::PING_SERVICE};
        config.localLocator = "mock:host=master1";
        cluster.addServer(config);

        config.services = {WireFormat::PING_SERVICE};
        config.localLocator = "mock:host=ping1";
        cluster.addServer(config);

        im = &cluster.contexts[0]->getMasterService()->indexletManager;
        ramcloud.construct("mock:");
        transport.construct(ramcloud->clientContext);

        ramcloud->clientContext->objectFinder->tableConfigFetcher.reset(
                new IndexLookupRpcRefresher);
        ramcloud->clientContext->transportManager->registerMock(
                transport.get());

    }

    ~IndexLookupTest()
    {
    }

    DISALLOW_COPY_AND_ASSIGN(IndexLookupTest);
};

TEST_F(IndexLookupTest, construction) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    EXPECT_EQ("mock:indexserver=0",
        indexLookup.lookupRpc.rpc->session->getServiceLocator());
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
}

// Rule 1:
// Handle the completion of a lookIndexKeys RPC.
TEST_F(IndexLookupTest, isReady_lookupComplete) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    const char *nextKey = "next key for rpc";
    size_t nextKeyLen = strlen(nextKey) + 1; // include null char

    Buffer *respBuffer = indexLookup.lookupRpc.rpc->response;

    respBuffer->emplaceAppend<WireFormat::ResponseCommon>()->status = STATUS_OK;
    // numHashes
    respBuffer->emplaceAppend<uint32_t>(10);
    // nextKeyLength
    respBuffer->emplaceAppend<uint16_t>(uint16_t(nextKeyLen));
    // nextKeyHash
    respBuffer->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        respBuffer->emplaceAppend<KeyHash>(i);
    }
    respBuffer->appendCopy(nextKey, (uint32_t) nextKeyLen);

    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(10U, indexLookup.lookupRpc.numHashes + indexLookup.numInserted);
    EXPECT_EQ(0U, indexLookup.nextKeyHash);
    EXPECT_EQ(0, strcmp(reinterpret_cast<char*>(indexLookup.nextKey), nextKey));
}

// Rule 2:
// Copy PKHashes from response buffer of lookup RPC into activeHashes
TEST_F(IndexLookupTest, isReady_activeHashes) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
        WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::FREE, indexLookup.lookupRpc.status);
    for (KeyHash i = 0; i < 10; i++) {
        EXPECT_EQ(i, indexLookup.activeHashes[i]);
    }
}

// Rule 3(a):
// Issue next lookup RPC if an RESULT_READY lookupIndexKeys RPC
// has no unread RPC
TEST_F(IndexLookupTest, isReady_issueNextLookup) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
            WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(1));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->response->emplaceAppend<char>('b');
    EXPECT_EQ("mock:indexserver=0",
                indexLookup.lookupRpc.rpc->session->getServiceLocator());
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    EXPECT_EQ("mock:indexserver=1",
            indexLookup.lookupRpc.rpc->session->getServiceLocator());
}

// Rule 3(b):
// If all lookup RPCs have completed, mark finishedLookup as true, which
// indicates no outgoing lookup RPC thereafter.
TEST_F(IndexLookupTest, isReady_allLookupCompleted) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
            WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ(IndexLookup::FREE, indexLookup.lookupRpc.status);
    EXPECT_TRUE(indexLookup.finishedLookup);
}

// Rule 5:
// Try to assign the current key hash to an existing RPC to the same server.
TEST_F(IndexLookupTest, isReady_assignPKHashesToSameServer) {
    TestLog::Enable _;
    IndexLookup indexLookup(ramcloud.get(), 10, azKeyRange);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<
        WireFormat::ResponseCommon>()->status = STATUS_OK;
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint32_t>(10);
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint16_t>(uint16_t(0));
    indexLookup.lookupRpc.rpc->response->emplaceAppend<uint64_t>(0);
    for (KeyHash i = 0; i < 10; i++) {
        indexLookup.lookupRpc.rpc->response->emplaceAppend<KeyHash>(i);
    }
    indexLookup.lookupRpc.rpc->completed();
    EXPECT_EQ(IndexLookup::SENT, indexLookup.lookupRpc.status);
    indexLookup.isReady();
    EXPECT_EQ("mock:dataserver=0",
               indexLookup.readRpcs[0].rpc->session->getServiceLocator());
    EXPECT_EQ(10U, indexLookup.readRpcs[0].numHashes);
    EXPECT_EQ(9U, indexLookup.readRpcs[0].maxPos);
    EXPECT_EQ(IndexLookup::SENT, indexLookup.readRpcs[0].status);
}

// Adds bogus index entries for an object that shouldn't be in range query.
TEST_F(IndexLookupTest, getNext_filtering) {
    ramcloud.construct(&context, "mock:host=coordinator");
    uint64_t tableId = ramcloud->createTable("table");
    ramcloud->createIndex(tableId, 1, 0);

    uint8_t numKeys = 2;

    KeyInfo keyList1[2];
    keyList1[0].keyLength = 11;
    keyList1[0].key = "primaryKey1";
    keyList1[1].keyLength = 1;
    keyList1[1].key = "a";

    KeyInfo keyList2[2];
    keyList2[0].keyLength = 11;
    keyList2[0].key = "primaryKey2";
    keyList2[1].keyLength = 1;
    keyList2[1].key = "b";

    KeyInfo keyList3[2];
    keyList3[0].keyLength = 11;
    keyList3[0].key = "primaryKey3";
    keyList3[1].keyLength = 1;
    keyList3[1].key = "c";

    ramcloud->write(tableId, numKeys, keyList1, "value1");
    ramcloud->write(tableId, numKeys, keyList2, "value2");
    ramcloud->write(tableId, numKeys, keyList3, "value3");

    Key primaryKey1(tableId, keyList1[0].key, keyList1[0].keyLength);
    uint64_t pkhash1 = primaryKey1.getHash();
    // Insert extra index entries corresponding to pkhash for primaryKey1.
    // We will ensure that these don't get returned on lookup.
    im->insertEntry(tableId, 1, "b1", 2, pkhash1);
    im->insertEntry(tableId, 1, "c1", 2, pkhash1);
    im->insertEntry(tableId, 1, "B1", 2, pkhash1);
    im->insertEntry(tableId, 1, "C1", 2, pkhash1);

    // Lookup for a key range such that the range contains some real index
    // entries (corresponding to objects) and some fake index entries (inserted
    // artificially above). Test that the objects get returned.

    IndexKey::IndexKeyRange keyRange1(1, "b", 1, "d", 1);
    IndexLookup indexLookup1(ramcloud.get(), tableId, keyRange1);

    EXPECT_TRUE(indexLookup1.getNext());
    Object* obj = indexLookup1.currentObject();
    EXPECT_STREQ("primaryKey2", StringUtil::binaryToString(
            obj->getKey(), obj->getKeyLength(0)).c_str());

    EXPECT_TRUE(indexLookup1.getNext());
    obj = indexLookup1.currentObject();
    EXPECT_STREQ("primaryKey3", StringUtil::binaryToString(
            obj->getKey(), obj->getKeyLength(0)).c_str());

    EXPECT_FALSE(indexLookup1.getNext());

    // Lookup for a key range such that it contains only fake index entries.
    // Test that nothing gets returned.
    IndexKey::IndexKeyRange keyRange2(1, "B", 1, "D", 1);
    IndexLookup indexLookup2(ramcloud.get(), tableId, keyRange2);

    EXPECT_FALSE(indexLookup2.getNext());
}
} // namespace ramcloud
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "FailureInfo.hxx"

class FailureInfo;

class ReferencedFailureInfo : public FailureInfo {
	unsigned refs = 1;

public:
	void Ref() noexcept {
		++refs;
	}

	void Unref() noexcept {
		if (--refs == 0)
			Destroy();
	}

	struct UnrefDisposer {
		void operator()(ReferencedFailureInfo *failure) const noexcept {
			failure->Unref();
		}
	};

protected:
	virtual void Destroy() = 0;
};

/**
 * Holds a (counted) reference to a #FailureInfo instance.
 */
class FailureRef {
	friend class FailurePtr;

	ReferencedFailureInfo &info;

public:
	explicit FailureRef(ReferencedFailureInfo &_info) noexcept;
	~FailureRef() noexcept;

	FailureRef(const FailureRef &) = delete;
	FailureRef &operator=(const FailureRef &) = delete;

	FailureInfo *operator->() {
		return &info;
	}

	FailureInfo &operator*() {
		return info;
	}
};

/**
 * Like #FailureRef, but manages a dynamic pointer.
 */
class FailurePtr {
	ReferencedFailureInfo *info = nullptr;

public:
	FailurePtr() = default;

	~FailurePtr() noexcept {
		if (info != nullptr)
			info->Unref();
	}

	FailurePtr(const FailurePtr &) = delete;
	FailurePtr &operator=(const FailurePtr &) = delete;

	operator bool() const {
		return info != nullptr;
	}

	FailurePtr &operator=(ReferencedFailureInfo &new_info) noexcept {
		if (info != nullptr)
			info->Unref();
		info = &new_info;
		info->Ref();
		return *this;
	}

	FailurePtr &operator=(FailureRef &new_ref) noexcept {
		return *this = new_ref.info;
	}

	FailureInfo *operator->() {
		return info;
	}

	FailureInfo &operator*() {
		return *info;
	}
};
<commit_msg>net/FailureRef: add FailurePtr move ctor/operator<commit_after>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "FailureInfo.hxx"

#include <utility>

class FailureInfo;

class ReferencedFailureInfo : public FailureInfo {
	unsigned refs = 1;

public:
	void Ref() noexcept {
		++refs;
	}

	void Unref() noexcept {
		if (--refs == 0)
			Destroy();
	}

	struct UnrefDisposer {
		void operator()(ReferencedFailureInfo *failure) const noexcept {
			failure->Unref();
		}
	};

protected:
	virtual void Destroy() = 0;
};

/**
 * Holds a (counted) reference to a #FailureInfo instance.
 */
class FailureRef {
	friend class FailurePtr;

	ReferencedFailureInfo &info;

public:
	explicit FailureRef(ReferencedFailureInfo &_info) noexcept;
	~FailureRef() noexcept;

	FailureRef(const FailureRef &) = delete;
	FailureRef &operator=(const FailureRef &) = delete;

	FailureInfo *operator->() {
		return &info;
	}

	FailureInfo &operator*() {
		return info;
	}
};

/**
 * Like #FailureRef, but manages a dynamic pointer.
 */
class FailurePtr {
	ReferencedFailureInfo *info = nullptr;

public:
	FailurePtr() = default;

	FailurePtr(FailurePtr &&src) noexcept
		:info(std::exchange(src.info, nullptr)) {}

	~FailurePtr() noexcept {
		if (info != nullptr)
			info->Unref();
	}

	FailurePtr(const FailurePtr &) = delete;
	FailurePtr &operator=(const FailurePtr &) = delete;

	operator bool() const {
		return info != nullptr;
	}

	FailurePtr &operator=(FailurePtr &&src) noexcept {
		using std::swap;
		swap(info, src.info);
		return *this;
	}

	FailurePtr &operator=(ReferencedFailureInfo &new_info) noexcept {
		if (info != nullptr)
			info->Unref();
		info = &new_info;
		info->Ref();
		return *this;
	}

	FailurePtr &operator=(FailureRef &new_ref) noexcept {
		return *this = new_ref.info;
	}

	FailureInfo *operator->() {
		return info;
	}

	FailureInfo &operator*() {
		return *info;
	}
};
<|endoftext|>


<commit_before>#ifdef _WIN32

#include "platform.h"
#include "imgui.h"
#include <Windows.h>
#include <assert.h>
#include <iostream>
#include <stdint.h>
#include <winnls.h>

wchar_t *utf8_to_wide(const char *s) {
	size_t len = utf8len(s);
	wchar_t *buf = (wchar_t *)malloc(sizeof(wchar_t) * (1 + len));
	mbstowcs(buf, s, len);
	buf[len] = 0;
	return buf;
}

char *wide_to_utf8(const wchar_t *s) {
	size_t len = 0;
	wchar_t c;
	for (const wchar_t *ss = s; 0 != (c = *ss); ++ss) {
		if (c < 0x80) {
			len += 1;
		} else if (c < 0x800) {
			len += 2;
		} else if (c >= 0xd800 && c < 0xdc00) {
			// surrogate pair
			len += 4;
			++ss;
		} else if (c >= 0xdc00 && c < 0xe000) {
			// pair end -- invalid sequence
			return nullptr;
		} else {
			len += 3;
		}
	}
	char *buf = (char *)malloc(1 + len);
	wcstombs(buf, s, len);
	buf[len] = 0;
	return buf;
}

char *file_as_buffer(size_t *buffer_size, const char *utf8_filename) {
	wchar_t *wide_filename = utf8_to_wide(utf8_filename);
	HANDLE file = CreateFile(wide_filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
	                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	free(wide_filename);
	if (file == INVALID_HANDLE_VALUE) {
		*buffer_size = 0;
		return nullptr;
	}

	LARGE_INTEGER filesize;
	GetFileSizeEx(file, &filesize);
	uint32_t sz = (uint32_t)filesize.QuadPart;
	assert(filesize.QuadPart == sz);
	*buffer_size = sz;

	char *buf = (char *)malloc(sz);
	uint32_t numRead = 0;
	ReadFile(file, buf, sz, (LPDWORD)&numRead, NULL);
	assert(numRead == sz);

	return buf;
}

char *show_file_picker() {
	OPENFILENAME ofn;
	wchar_t filename[1024];
	filename[0] = 0;
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = (HWND)ImGui::GetIO().ImeWindowHandle;
	ofn.lpstrFilter = L"BRD Files\0*.brd\0All Files\0*.*\0\0";
	ofn.lpstrFile = filename;
	ofn.nMaxFile = 1024;
	if (GetOpenFileName(&ofn)) {
		return wide_to_utf8(filename);
	}
	return nullptr;
}

// Not caring about XP. If this is a concern, find a replacement for CompareStringEx()
const std::vector<char> load_font(const std::string &name) {
	std::vector<char> data;
	HFONT fontHandle;

	wchar_t *wname = utf8_to_wide(name.c_str());

	fontHandle = CreateFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name.empty() ? NULL : wname);
	if (!fontHandle) {
		std::cerr << "CreateFont failed" << std::endl;
		free(wname);
		return data;
	}
	HDC hdc = ::CreateCompatibleDC(NULL);
	if (hdc != NULL) {
		::SelectObject(hdc, fontHandle);

		int ncount = ::GetTextFaceW(hdc, 0, nullptr);
		LPWSTR fname = new wchar_t[ncount];
		::GetTextFaceW(hdc, ncount, fname);

		if (!name.empty() &&
		    ::CompareStringEx(NULL, NORM_IGNORECASE, wname, name.size(), fname, ncount - 1, NULL,
		                      NULL, 0) != CSTR_EQUAL) { // We didn't get the font we requested
			free(wname);
			return data;
		}

		free(wname);

		const size_t size = ::GetFontData(hdc, 0, 0, NULL, 0);
		if (size > 0) {
			char *buffer = new char[size];
			if (::GetFontData(hdc, 0, 0, buffer, size) == size) {
				data = std::vector<char>(buffer, buffer + size);
			}
			delete[] buffer;
		}
		::DeleteDC(hdc);
	}
	DeleteObject(fontHandle);
	return data;
}

#endif // _WIN32
<commit_msg>GetFontData in some cases returns GDI_ERROR Fixes OpenBoardView/OpenBoardView/#42<commit_after>#ifdef _WIN32

#include "platform.h"
#include "imgui.h"
#include <Windows.h>
#include <assert.h>
#include <iostream>
#include <stdint.h>
#include <winnls.h>

wchar_t *utf8_to_wide(const char *s) {
	size_t len = utf8len(s);
	wchar_t *buf = (wchar_t *)malloc(sizeof(wchar_t) * (1 + len));
	mbstowcs(buf, s, len);
	buf[len] = 0;
	return buf;
}

char *wide_to_utf8(const wchar_t *s) {
	size_t len = 0;
	wchar_t c;
	for (const wchar_t *ss = s; 0 != (c = *ss); ++ss) {
		if (c < 0x80) {
			len += 1;
		} else if (c < 0x800) {
			len += 2;
		} else if (c >= 0xd800 && c < 0xdc00) {
			// surrogate pair
			len += 4;
			++ss;
		} else if (c >= 0xdc00 && c < 0xe000) {
			// pair end -- invalid sequence
			return nullptr;
		} else {
			len += 3;
		}
	}
	char *buf = (char *)malloc(1 + len);
	wcstombs(buf, s, len);
	buf[len] = 0;
	return buf;
}

char *file_as_buffer(size_t *buffer_size, const char *utf8_filename) {
	wchar_t *wide_filename = utf8_to_wide(utf8_filename);
	HANDLE file = CreateFile(wide_filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
	                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	free(wide_filename);
	if (file == INVALID_HANDLE_VALUE) {
		*buffer_size = 0;
		return nullptr;
	}

	LARGE_INTEGER filesize;
	GetFileSizeEx(file, &filesize);
	uint32_t sz = (uint32_t)filesize.QuadPart;
	assert(filesize.QuadPart == sz);
	*buffer_size = sz;

	char *buf = (char *)malloc(sz);
	uint32_t numRead = 0;
	ReadFile(file, buf, sz, (LPDWORD)&numRead, NULL);
	assert(numRead == sz);

	return buf;
}

char *show_file_picker() {
	OPENFILENAME ofn;
	wchar_t filename[1024];
	filename[0] = 0;
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = (HWND)ImGui::GetIO().ImeWindowHandle;
	ofn.lpstrFilter = L"BRD Files\0*.brd\0All Files\0*.*\0\0";
	ofn.lpstrFile = filename;
	ofn.nMaxFile = 1024;
	if (GetOpenFileName(&ofn)) {
		return wide_to_utf8(filename);
	}
	return nullptr;
}

// Not caring about XP. If this is a concern, find a replacement for CompareStringEx()
const std::vector<char> load_font(const std::string &name) {
	std::vector<char> data;
	HFONT fontHandle;

	wchar_t *wname = utf8_to_wide(name.c_str());

	fontHandle = CreateFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name.empty() ? NULL : wname);
	if (!fontHandle) {
		std::cerr << "CreateFont failed" << std::endl;
		free(wname);
		return data;
	}
	HDC hdc = ::CreateCompatibleDC(NULL);
	if (hdc != NULL) {
		::SelectObject(hdc, fontHandle);

		int ncount = ::GetTextFaceW(hdc, 0, nullptr);
		LPWSTR fname = new wchar_t[ncount];
		::GetTextFaceW(hdc, ncount, fname);

		if (!name.empty() &&
		    ::CompareStringEx(NULL, NORM_IGNORECASE, wname, name.size(), fname, ncount - 1, NULL,
		                      NULL, 0) != CSTR_EQUAL) { // We didn't get the font we requested
			free(wname);
			return data;
		}

		free(wname);

		const size_t size = ::GetFontData(hdc, 0, 0, NULL, 0);
		if (size > 0 && size != GDI_ERROR) {
			char *buffer = new char[size];
			if (::GetFontData(hdc, 0, 0, buffer, size) == size) {
				data = std::vector<char>(buffer, buffer + size);
			}
			delete[] buffer;
		}
		::DeleteDC(hdc);
	}
	DeleteObject(fontHandle);
	return data;
}

#endif // _WIN32
<|endoftext|>


<commit_before>//! \file

#include <json/json.h>

#include "Article.h"
#include "JsonSerializer.h"

namespace WikiWalker
{
  /*! Get article links in an array.
   * Basically undoing the Wikipedia to article conversion...
   * \param article pointer to article which links should be extracted
   * \return Json::Value array with titles as string
   * \todo should / could be a member function, but then I'd have to expose
   * Json::Value, which is ugly and clutters up other classes...
   */
  static Json::Value getArticleLinks(const Article* article)
  {
    Json::Value array(Json::ValueType::arrayValue);

    for(auto ali = article->linkBegin(); ali != article->linkEnd(); ali++) {
      auto a = ali->lock();
      if(a != nullptr) {
        std::string tit = a->title();
        array.append(Json::Value(tit));
      }
    }

    return array;
  }

  /*! Convert article to string representation of JSON representation.
   * \param a pointer to article to be converted
   * \return json as string
   * \internal uses the following format:
   * {"title":{"forward_links":[...]}}
   */
  static std::string convertToJson(const ArticleCollection& ac)
  {
    Json::Value val(Json::ValueType::objectValue);

    for(auto ar : ac) {
      Json::Value linkObj(Json::ValueType::objectValue);

      if(ar.second->analyzed()) {
        linkObj["forward_links"] = getArticleLinks(ar.second.get());
      } else {
        linkObj["forward_links"] = Json::Value::nullSingleton();
      }

      val[ar.first] = linkObj;
    }

    Json::StreamWriterBuilder swb;
    swb["indentation"] = "";
    return Json::writeString(swb, val);
  }

  /*! Convert article collection to string representation of JSON
   * representation.
   * \param ac reference to article collection to be converted
   * \return json as string
   * \internal uses the following format:
   * {"title":{"forward_links":[...]}, "title2":{"forward_links":[...]}, ...}
   */
  static std::string convertToJson(const Article* a)
  {
    Json::Value val(Json::ValueType::objectValue);

    Json::Value linkObj(Json::ValueType::objectValue);

    if(a->analyzed()) {
      linkObj["forward_links"] = getArticleLinks(a);
    } else {
      linkObj["forward_links"] = Json::Value::nullSingleton();
    }

    val[a->title()] = linkObj;

    Json::StreamWriterBuilder swb;
    swb["indentation"] = "";
    return Json::writeString(swb, val);
  }

  void JsonSerializer::serialize(const ArticleCollection& collection,
                                 std::ostream& outstream)
  {
    outstream << convertToJson(collection);
  }
}
<commit_msg>Remove single article serialization<commit_after>//! \file

#include <json/json.h>

#include "Article.h"
#include "JsonSerializer.h"

namespace WikiWalker
{
  /*! Get article links in an array.
   * Basically undoing the Wikipedia to article conversion...
   * \param article pointer to article which links should be extracted
   * \return Json::Value array with titles as string
   * \todo should / could be a member function, but then I'd have to expose
   * Json::Value, which is ugly and clutters up other classes...
   */
  static Json::Value getArticleLinks(const Article* article)
  {
    Json::Value array(Json::ValueType::arrayValue);

    for(auto ali = article->linkBegin(); ali != article->linkEnd(); ali++) {
      auto a = ali->lock();
      if(a != nullptr) {
        std::string tit = a->title();
        array.append(Json::Value(tit));
      }
    }

    return array;
  }

  /*! Convert article to string representation of JSON representation.
   * \param a pointer to article to be converted
   * \return json as string
   * \internal uses the following format:
   * {"title":{"forward_links":[...]}, "title2":{"forward_links":[...]}, ...}
   */
  static std::string convertToJson(const ArticleCollection& ac)
  {
    Json::Value val(Json::ValueType::objectValue);

    for(auto ar : ac) {
      Json::Value linkObj(Json::ValueType::objectValue);

      if(ar.second->analyzed()) {
        linkObj["forward_links"] = getArticleLinks(ar.second.get());
      } else {
        linkObj["forward_links"] = Json::Value::nullSingleton();
      }

      val[ar.first] = linkObj;
    }

    Json::StreamWriterBuilder swb;
    swb["indentation"] = "";
    return Json::writeString(swb, val);
  }

  void JsonSerializer::serialize(const ArticleCollection& collection,
                                 std::ostream& outstream)
  {
    outstream << convertToJson(collection);
  }
}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "include/librados.h"
#include "config.h"
#include "common/common_init.h"

#include <iostream>

#include <stdlib.h>
#include <time.h>

void usage()
{
  cerr << "usage: radostool [options] [commands]" << std::endl;
  /*  cerr << "If no commands are specified, enter interactive mode.\n";
  cerr << "Commands:" << std::endl;
  cerr << "   stop              -- cleanly shut down file system" << std::endl
       << "   (osd|pg|mds) stat -- get monitor subsystem status" << std::endl
       << "   ..." << std::endl;
  */
  cerr << "Options:" << std::endl;
  cerr << "   -i infile\n";
  cerr << "   -o outfile\n";
  cerr << "        specify input or output file (for certain commands)\n";
  generic_client_usage();
}

int main(int argc, const char **argv)
{
  DEFINE_CONF_VARS(usage);
  vector<const char*> args;
  argv_to_vec(argc, argv, args);
  env_to_vec(args);
  common_init(args, "rados", false);

  vector<const char*> nargs;
  bufferlist indata, outdata;
  const char *outfile = 0;

  const char *pool = 0;

  FOR_EACH_ARG(args) {
    if (CONF_ARG_EQ("out_file", 'o')) {
      CONF_SAFE_SET_ARG_VAL(&outfile, OPT_STR);
    } else if (CONF_ARG_EQ("in_data", 'i')) {
      const char *fname;
      CONF_SAFE_SET_ARG_VAL(&fname, OPT_STR);
      int r = indata.read_file(fname);
      if (r < 0) {
	cerr << "error reading " << fname << ": " << strerror(-r) << std::endl;
	exit(0);
      } else {
	cout << "read " << indata.length() << " bytes from " << fname << std::endl;
      }
    } else if (CONF_ARG_EQ("pool", 'p')) {
      CONF_SAFE_SET_ARG_VAL(&pool, OPT_STR);
    } else if (CONF_ARG_EQ("help", 'h')) {
      usage();
    } else if (args[i][0] == '-' && nargs.empty()) {
      cerr << "unrecognized option " << args[i] << std::endl;
      usage();
    } else
      nargs.push_back(args[i]);
  }

  if (nargs.empty())
    usage();

  // open rados
  Rados rados;
  if (rados.initialize(0, NULL) < 0) {
     cerr << "couldn't initialize rados!" << std::endl;
     exit(1);
  }

  // open pool?
  rados_pool_t p;
  if (pool) {
    int r = rados.open_pool(pool, &p);
    if (r < 0) {
      cerr << "error opening pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }
  }

  // list pools?
  if (strcmp(nargs[0], "lspools") == 0) {
    vector<string> vec;
    rados.list_pools(vec);
    for (vector<string>::iterator i = vec.begin(); i != vec.end(); ++i)
      cout << *i << std::endl;

  } else if (strcmp(nargs[0], "ls") == 0) {
    if (!pool)
      usage();

    Rados::ListCtx ctx;
    while (1) {
      list<object_t> vec;
      int r = rados.list(p, 1 << 10, vec, ctx);
      cout << "list result=" << r << " entries=" << vec.size() << std::endl;
      if (r < 0) {
	cerr << "got error: " << strerror(-r) << std::endl;
	break;
      }
      if (vec.empty())
	break;
      for (list<object_t>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	cout << *iter << std::endl;
    }

  } else if (strcmp(nargs[0], "get") == 0) {
    if (!pool || nargs.size() < 2)
      usage();
    object_t oid(nargs[1]);
    int r = rados.read(p, oid, 0, outdata, 0);
    if (r < 0) {
      cerr << "error reading " << oid << " from pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }

  } else if (strcmp(nargs[0], "put") == 0) {
    if (!pool || nargs.size() < 2)
      usage();
    if (!indata.length()) {
      cerr << "must specify input file" << std::endl;
      usage();
    }
    object_t oid(nargs[1]);
    int r = rados.write(p, oid, 0, indata, indata.length());
    if (r < 0) {
      cerr << "error writing " << oid << " to pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }

  } else {
    cerr << "unrecognized command " << nargs[0] << std::endl;
    usage();
  }

  // write data?
  int len = outdata.length();
  if (len) {
    if (outfile) {
      if (strcmp(outfile, "-") == 0) {
	::write(1, outdata.c_str(), len);
      } else {
	outdata.write_file(outfile);
      }
      generic_dout(0) << "wrote " << len << " byte payload to " << outfile << dendl;
    } else {
      generic_dout(0) << "got " << len << " byte payload, discarding (specify -o <outfile)" << dendl;
    }
  }

  if (pool)
    rados.close_pool(p);

  rados_deinitialize();
  return 0;
}
/*
    // pool
    const char *cmd = nargs[0];

  if (!pool)
    usage();

  // init rados
  Rados rados;
  if (rados.initialize(0, NULL) < 0) {
     cerr << "couldn't initialize rados!" << std::endl;
     exit(1);
  }

  rados_pool_t pool;
  int r = rados.open_pool("data", &pool);
  cout << "open pool result = " << r << " pool = " << pool << std::endl;

  rados.write(pool, oid, 0, bl, bl.length());
  rados.write(pool, oid, 0, bl, bl.length() - 1);
  rados.write(pool, oid, 0, bl, bl.length() - 2);
  rados.write(pool, oid, 0, bl, bl.length() - 3);
  rados.write(pool, oid, 0, bl, bl.length() - 4);
  r = rados.exec(pool, oid, "crypto", "md5", bl, bl2);
  cout << "exec returned " << r << std::endl;
  const unsigned char *md5 = (const unsigned char *)bl2.c_str();
  char md5_str[bl2.length()*2 + 1];
  buf_to_hex(md5, bl2.length(), md5_str);
  cout << "md5 result=" << md5_str << std::endl;

  r = rados.exec(pool, oid, "crypto", "sha1", bl, bl2);
  cout << "exec returned " << r << std::endl;
  const unsigned char *sha1 = (const unsigned char *)bl2.c_str();
  char sha1_str[bl2.length()*2 + 1];
  buf_to_hex(sha1, bl2.length(), sha1_str);
  cout << "sha1 result=" << sha1_str << std::endl;

  int size = rados.read(pool, oid, 0, bl2, 128);
  cout << "read result=" << bl2.c_str() << std::endl;
  cout << "size=" << size << std::endl;

  Rados::ListCtx ctx;
  int entries;
  do {
    list<object_t> vec;
    r = rados.list(pool, 2, vec, ctx);
    entries = vec.size();
    cout << "list result=" << r << " entries=" << entries << std::endl;
    list<object_t>::iterator iter;
    for (iter = vec.begin(); iter != vec.end(); ++iter) {
      cout << *iter << std::endl;
    }
  } while (entries);
#if 0
  r = rados.remove(pool, oid);
  cout << "remove result=" << r << std::endl;
  rados.close_pool(pool);
#endif

  return 0;
}

*/
<commit_msg>radostool: cleanup<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "include/librados.h"
#include "config.h"
#include "common/common_init.h"

#include <iostream>

#include <stdlib.h>
#include <time.h>

void usage()
{
  cerr << "usage: radostool [options] [commands]" << std::endl;
  /*  cerr << "If no commands are specified, enter interactive mode.\n";
  cerr << "Commands:" << std::endl;
  cerr << "   stop              -- cleanly shut down file system" << std::endl
       << "   (osd|pg|mds) stat -- get monitor subsystem status" << std::endl
       << "   ..." << std::endl;
  */
  cerr << "Options:" << std::endl;
  cerr << "   -i infile\n";
  cerr << "   -o outfile\n";
  cerr << "        specify input or output file (for certain commands)\n";
  generic_client_usage();
}

int main(int argc, const char **argv)
{
  DEFINE_CONF_VARS(usage);
  vector<const char*> args;
  argv_to_vec(argc, argv, args);
  env_to_vec(args);
  common_init(args, "rados", false);

  vector<const char*> nargs;
  bufferlist indata, outdata;
  const char *outfile = 0;

  const char *pool = 0;

  FOR_EACH_ARG(args) {
    if (CONF_ARG_EQ("out_file", 'o')) {
      CONF_SAFE_SET_ARG_VAL(&outfile, OPT_STR);
    } else if (CONF_ARG_EQ("in_data", 'i')) {
      const char *fname;
      CONF_SAFE_SET_ARG_VAL(&fname, OPT_STR);
      int r = indata.read_file(fname);
      if (r < 0) {
	cerr << "error reading " << fname << ": " << strerror(-r) << std::endl;
	exit(0);
      } else {
	cout << "read " << indata.length() << " bytes from " << fname << std::endl;
      }
    } else if (CONF_ARG_EQ("pool", 'p')) {
      CONF_SAFE_SET_ARG_VAL(&pool, OPT_STR);
    } else if (CONF_ARG_EQ("help", 'h')) {
      usage();
    } else if (args[i][0] == '-' && nargs.empty()) {
      cerr << "unrecognized option " << args[i] << std::endl;
      usage();
    } else
      nargs.push_back(args[i]);
  }

  if (nargs.empty())
    usage();

  // open rados
  Rados rados;
  if (rados.initialize(0, NULL) < 0) {
     cerr << "couldn't initialize rados!" << std::endl;
     exit(1);
  }

  // open pool?
  rados_pool_t p;
  if (pool) {
    int r = rados.open_pool(pool, &p);
    if (r < 0) {
      cerr << "error opening pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }
  }

  // list pools?
  if (strcmp(nargs[0], "lspools") == 0) {
    vector<string> vec;
    rados.list_pools(vec);
    for (vector<string>::iterator i = vec.begin(); i != vec.end(); ++i)
      cout << *i << std::endl;

  } else if (strcmp(nargs[0], "ls") == 0) {
    if (!pool)
      usage();

    Rados::ListCtx ctx;
    while (1) {
      list<object_t> vec;
      int r = rados.list(p, 1 << 10, vec, ctx);
      cout << "list result=" << r << " entries=" << vec.size() << std::endl;
      if (r < 0) {
	cerr << "got error: " << strerror(-r) << std::endl;
	break;
      }
      if (vec.empty())
	break;
      for (list<object_t>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	cout << *iter << std::endl;
    }

  } else if (strcmp(nargs[0], "get") == 0) {
    if (!pool || nargs.size() < 2)
      usage();
    object_t oid(nargs[1]);
    int r = rados.read(p, oid, 0, outdata, 0);
    if (r < 0) {
      cerr << "error reading " << oid << " from pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }

  } else if (strcmp(nargs[0], "put") == 0) {
    if (!pool || nargs.size() < 2)
      usage();
    if (!indata.length()) {
      cerr << "must specify input file" << std::endl;
      usage();
    }
    object_t oid(nargs[1]);
    int r = rados.write(p, oid, 0, indata, indata.length());
    if (r < 0) {
      cerr << "error writing " << oid << " to pool " << pool << ": " << strerror(-r) << std::endl;
      exit(0);
    }

  } else {
    cerr << "unrecognized command " << nargs[0] << std::endl;
    usage();
  }

  // write data?
  int len = outdata.length();
  if (len) {
    if (outfile) {
      if (strcmp(outfile, "-") == 0) {
	::write(1, outdata.c_str(), len);
      } else {
	outdata.write_file(outfile);
      }
      generic_dout(0) << "wrote " << len << " byte payload to " << outfile << dendl;
    } else {
      generic_dout(0) << "got " << len << " byte payload, discarding (specify -o <outfile)" << dendl;
    }
  }

  if (pool)
    rados.close_pool(p);

  rados_deinitialize();
  return 0;
}
<|endoftext|>


<commit_before>/*
  NUI3 - C++ cross-platform GUI framework for OpenGL based applications
  Copyright (C) 2002-2003 Sebastien Metrot

  licence: see nui3/LICENCE.TXT
*/

#include "nui.h"
#include "nui.h"
#include "nuiApplication.h"
#include "nuiPane.h"
#include "nuiXML.h"
#include "nuiDrawContext.h"

nuiPane::nuiPane(const nuiColor& rFillColor, const nuiColor& rStrokeColor, nuiShapeMode ShapeMode, nuiBlendFunc BlendFunc)
 : nuiSimpleContainer()
{
  SetObjectClass(_T("nuiPane"));
  mInterceptMouse = false;

  mFillColor = rFillColor;
  mStrokeColor = rStrokeColor;

  mShapeMode = ShapeMode;
  mBlendFunc = BlendFunc;
  mLineWidth = 1;
  mCanRespectConstraint = true;

  NUI_ADD_EVENT(ClickedMouse);
  NUI_ADD_EVENT(UnclickedMouse);
  NUI_ADD_EVENT(MovedMouse);

  mpShape = NULL;
  SetCurve(0);
}

bool nuiPane::Load(const nuiXMLNode* pNode)
{
	LoadAttributes(pNode);
	LoadChildren(pNode);

  mInterceptMouse = nuiGetBool ( pNode, _T("InterceptMouse"), false);
  mLineWidth = nuiGetVal(pNode, _T("LineWidth"), 1.0f);
  mCanRespectConstraint = true;

  NUI_ADD_EVENT(ClickedMouse);
  NUI_ADD_EVENT(UnclickedMouse);
  NUI_ADD_EVENT(MovedMouse);

  mpShape = NULL;
  SetCurve(0);

  return true;
}

bool nuiPane::LoadAttributes(const nuiXMLNode* pNode)
{
	return nuiSimpleContainer::LoadAttributes(pNode);
}

bool nuiPane::LoadChildren(const nuiXMLNode* pNode)
{
	return nuiSimpleContainer::LoadChildren(pNode);
}

nuiXMLNode* nuiPane::Serialize(nuiXMLNode* pParentNode, bool Recursive) const
{
	nuiXMLNode* paneNode = SerializeAttributes(pParentNode, Recursive);
	SerializeChildren(paneNode, Recursive);

  return paneNode;
}

void nuiPane::SerializeChildren(nuiXMLNode* pParentNode, bool Recursive) const
{
	nuiContainer::SerializeChildren(pParentNode, Recursive);
}

nuiXMLNode* nuiPane::SerializeAttributes(nuiXMLNode* pParentNode, bool Recursive) const
{
	return nuiContainer::SerializeAttributes(pParentNode, Recursive);
}

nuiPane::~nuiPane()
{
  delete mpShape;
}

bool nuiPane::Draw(nuiDrawContext* pContext)
{
  pContext->PushState();
  pContext->ResetClipShape();

  pContext->EnableBlending(true);
  pContext->SetBlendFunc(mBlendFunc);

  pContext->SetFillColor(mFillColor);
  pContext->SetStrokeColor(mStrokeColor);
  pContext->EnableAntialiasing(true);
  pContext->SetLineWidth(mLineWidth);

  if (mCurve != 0)
  {
    pContext->DrawShape(mpShape, mShapeMode);
  }
  else
  {
    nuiRect rect = nuiRect(0.f,0.f,mRect.GetWidth(), mRect.GetHeight());
    pContext->DrawRect(rect, mShapeMode);
  }
  pContext->PopState();

  DrawChildren(pContext);
  return true;
}

bool nuiPane::MouseClicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  ClickedMouse(X,Y,Button);
  return mInterceptMouse;
}

bool nuiPane::MouseUnclicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  UnclickedMouse(X,Y,Button);
  return mInterceptMouse;
}

bool nuiPane::MouseMoved  (nuiSize X, nuiSize Y)
{
  MovedMouse(X,Y);
  return mInterceptMouse;
}

void nuiPane::SetInterceptMouse(bool intercept)
{
  mInterceptMouse = intercept;
}

bool nuiPane::GetInterceptMouse()
{
  return mInterceptMouse;
}

bool nuiPane::SetRect(const nuiRect& rRect)
{
  bool reload = !(mRect == rRect);

  nuiRect r(rRect.Size());

  nuiWidget::LayoutConstraint constraint(mConstraint);

  if (mCurve != 0)
  {
    r.Grow((nuiSize)ToNearest(-mCurve * .5f), (nuiSize)ToNearest(-mCurve * .5f));
    r.RoundToNearest();

    constraint.mMaxWidth -= (nuiSize)ToNearest(mCurve * .5f);
    constraint.mMaxHeight -= (nuiSize)ToNearest(mCurve * .5f);
  }

  IteratorPtr pIt;
  for (pIt = GetFirstChild(); pIt && pIt->IsValid(); GetNextChild(pIt))
  {
    nuiWidgetPtr pItem = pIt->GetWidget();
    if (mCurve != 0)
      pItem->SetLayoutConstraint(constraint);
    pItem->SetLayout(r);
  }
  delete pIt;

  nuiWidget::SetRect(rRect);

  if (reload)
    SetCurve(mCurve);

  return true;
}

void nuiPane::SetCurve(float curve)
{
  mCurve = curve;
  delete mpShape;
  if (curve != 0)
  mpShape = new nuiShape();
  mpShape->AddRoundRect(mRect.Size(), curve);
}

void nuiPane::SetLineWidth(float Width)
{
  mLineWidth = Width;
  Invalidate();
}

void nuiPane::SetFillColor(const nuiColor& rFillColor)
{
  mFillColor = rFillColor;
  Invalidate();
}

void nuiPane::SetStrokeColor(const nuiColor& rStrokeColor)
{
  mStrokeColor = rStrokeColor;
  Invalidate();
}

const nuiColor& nuiPane::GetFillColor() const
{
  return mFillColor;
}

const nuiColor& nuiPane::GetStrokeColor() const
{
  return mStrokeColor;
}

void nuiPane::SetShapeMode(nuiShapeMode shapeMode)
{
  mShapeMode = shapeMode;
  Invalidate();
}

nuiRect nuiPane::CalcIdealSize()
{
  nuiRect temp;

  nuiWidget::LayoutConstraint constraint(mConstraint);
  if (mCurve != 0)
  {
    constraint.mMaxWidth -= (nuiSize)ToNearest(mCurve * .5f);
    constraint.mMaxHeight -= (nuiSize)ToNearest(mCurve * .5f);
  }

  IteratorPtr pIt;
  for (pIt = GetFirstChild(); pIt && pIt->IsValid(); GetNextChild(pIt))
  {
    nuiWidgetPtr pItem = pIt->GetWidget();
    if (mCurve != 0)
      pItem->SetLayoutConstraint(constraint);
    nuiRect t = pItem->GetIdealRect();
    temp.Union(t,temp); // Dummy call. Only the side effect is important: the object recalculates its layout.
    //NGL_OUT(_T("    PaneItem rect %ls\n"), t.GetValue().GetChars());
  }
  delete pIt;

  if (mCurve != 0)
  {
    temp.Grow((nuiSize)ToNearest(mCurve * .5f), (nuiSize)ToNearest(mCurve * .5f));
    temp.RoundToBiggest();
  }

  DebugRefreshInfo();

  temp.MoveTo(0,0);

  //NGL_OUT(_T("    Pane rect %ls\n"), mIdealRect.GetValue().GetChars());
  return temp;
}
<commit_msg>fix missing indent<commit_after>/*
  NUI3 - C++ cross-platform GUI framework for OpenGL based applications
  Copyright (C) 2002-2003 Sebastien Metrot

  licence: see nui3/LICENCE.TXT
*/

#include "nui.h"
#include "nui.h"
#include "nuiApplication.h"
#include "nuiPane.h"
#include "nuiXML.h"
#include "nuiDrawContext.h"

nuiPane::nuiPane(const nuiColor& rFillColor, const nuiColor& rStrokeColor, nuiShapeMode ShapeMode, nuiBlendFunc BlendFunc)
 : nuiSimpleContainer()
{
  SetObjectClass(_T("nuiPane"));
  mInterceptMouse = false;

  mFillColor = rFillColor;
  mStrokeColor = rStrokeColor;

  mShapeMode = ShapeMode;
  mBlendFunc = BlendFunc;
  mLineWidth = 1;
  mCanRespectConstraint = true;

  NUI_ADD_EVENT(ClickedMouse);
  NUI_ADD_EVENT(UnclickedMouse);
  NUI_ADD_EVENT(MovedMouse);

  mpShape = NULL;
  SetCurve(0);
}

bool nuiPane::Load(const nuiXMLNode* pNode)
{
	LoadAttributes(pNode);
	LoadChildren(pNode);

  mInterceptMouse = nuiGetBool ( pNode, _T("InterceptMouse"), false);
  mLineWidth = nuiGetVal(pNode, _T("LineWidth"), 1.0f);
  mCanRespectConstraint = true;

  NUI_ADD_EVENT(ClickedMouse);
  NUI_ADD_EVENT(UnclickedMouse);
  NUI_ADD_EVENT(MovedMouse);

  mpShape = NULL;
  SetCurve(0);

  return true;
}

bool nuiPane::LoadAttributes(const nuiXMLNode* pNode)
{
	return nuiSimpleContainer::LoadAttributes(pNode);
}

bool nuiPane::LoadChildren(const nuiXMLNode* pNode)
{
	return nuiSimpleContainer::LoadChildren(pNode);
}

nuiXMLNode* nuiPane::Serialize(nuiXMLNode* pParentNode, bool Recursive) const
{
	nuiXMLNode* paneNode = SerializeAttributes(pParentNode, Recursive);
	SerializeChildren(paneNode, Recursive);

  return paneNode;
}

void nuiPane::SerializeChildren(nuiXMLNode* pParentNode, bool Recursive) const
{
	nuiContainer::SerializeChildren(pParentNode, Recursive);
}

nuiXMLNode* nuiPane::SerializeAttributes(nuiXMLNode* pParentNode, bool Recursive) const
{
	return nuiContainer::SerializeAttributes(pParentNode, Recursive);
}

nuiPane::~nuiPane()
{
  delete mpShape;
}

bool nuiPane::Draw(nuiDrawContext* pContext)
{
  pContext->PushState();
  pContext->ResetClipShape();

  pContext->EnableBlending(true);
  pContext->SetBlendFunc(mBlendFunc);

  pContext->SetFillColor(mFillColor);
  pContext->SetStrokeColor(mStrokeColor);
  pContext->EnableAntialiasing(true);
  pContext->SetLineWidth(mLineWidth);

  if (mCurve != 0)
  {
    pContext->DrawShape(mpShape, mShapeMode);
  }
  else
  {
    nuiRect rect = nuiRect(0.f,0.f,mRect.GetWidth(), mRect.GetHeight());
    pContext->DrawRect(rect, mShapeMode);
  }
  pContext->PopState();

  DrawChildren(pContext);
  return true;
}

bool nuiPane::MouseClicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  ClickedMouse(X,Y,Button);
  return mInterceptMouse;
}

bool nuiPane::MouseUnclicked  (nuiSize X, nuiSize Y, nglMouseInfo::Flags Button)
{
  UnclickedMouse(X,Y,Button);
  return mInterceptMouse;
}

bool nuiPane::MouseMoved  (nuiSize X, nuiSize Y)
{
  MovedMouse(X,Y);
  return mInterceptMouse;
}

void nuiPane::SetInterceptMouse(bool intercept)
{
  mInterceptMouse = intercept;
}

bool nuiPane::GetInterceptMouse()
{
  return mInterceptMouse;
}

bool nuiPane::SetRect(const nuiRect& rRect)
{
  bool reload = !(mRect == rRect);

  nuiRect r(rRect.Size());

  nuiWidget::LayoutConstraint constraint(mConstraint);

  if (mCurve != 0)
  {
    r.Grow((nuiSize)ToNearest(-mCurve * .5f), (nuiSize)ToNearest(-mCurve * .5f));
    r.RoundToNearest();

    constraint.mMaxWidth -= (nuiSize)ToNearest(mCurve * .5f);
    constraint.mMaxHeight -= (nuiSize)ToNearest(mCurve * .5f);
  }

  IteratorPtr pIt;
  for (pIt = GetFirstChild(); pIt && pIt->IsValid(); GetNextChild(pIt))
  {
    nuiWidgetPtr pItem = pIt->GetWidget();
    if (mCurve != 0)
      pItem->SetLayoutConstraint(constraint);
    pItem->SetLayout(r);
  }
  delete pIt;

  nuiWidget::SetRect(rRect);

  if (reload)
    SetCurve(mCurve);

  return true;
}

void nuiPane::SetCurve(float curve)
{
  mCurve = curve;
  delete mpShape;
  if (curve != 0) {
    mpShape = new nuiShape();
    mpShape->AddRoundRect(mRect.Size(), curve);
  }
}

void nuiPane::SetLineWidth(float Width)
{
  mLineWidth = Width;
  Invalidate();
}

void nuiPane::SetFillColor(const nuiColor& rFillColor)
{
  mFillColor = rFillColor;
  Invalidate();
}

void nuiPane::SetStrokeColor(const nuiColor& rStrokeColor)
{
  mStrokeColor = rStrokeColor;
  Invalidate();
}

const nuiColor& nuiPane::GetFillColor() const
{
  return mFillColor;
}

const nuiColor& nuiPane::GetStrokeColor() const
{
  return mStrokeColor;
}

void nuiPane::SetShapeMode(nuiShapeMode shapeMode)
{
  mShapeMode = shapeMode;
  Invalidate();
}

nuiRect nuiPane::CalcIdealSize()
{
  nuiRect temp;

  nuiWidget::LayoutConstraint constraint(mConstraint);
  if (mCurve != 0)
  {
    constraint.mMaxWidth -= (nuiSize)ToNearest(mCurve * .5f);
    constraint.mMaxHeight -= (nuiSize)ToNearest(mCurve * .5f);
  }

  IteratorPtr pIt;
  for (pIt = GetFirstChild(); pIt && pIt->IsValid(); GetNextChild(pIt))
  {
    nuiWidgetPtr pItem = pIt->GetWidget();
    if (mCurve != 0)
      pItem->SetLayoutConstraint(constraint);
    nuiRect t = pItem->GetIdealRect();
    temp.Union(t,temp); // Dummy call. Only the side effect is important: the object recalculates its layout.
    //NGL_OUT(_T("    PaneItem rect %ls\n"), t.GetValue().GetChars());
  }
  delete pIt;

  if (mCurve != 0)
  {
    temp.Grow((nuiSize)ToNearest(mCurve * .5f), (nuiSize)ToNearest(mCurve * .5f));
    temp.RoundToBiggest();
  }

  DebugRefreshInfo();

  temp.MoveTo(0,0);

  //NGL_OUT(_T("    Pane rect %ls\n"), mIdealRect.GetValue().GetChars());
  return temp;
}
<|endoftext|>


<commit_before> /** @file posix_periodic.cpp
 *  @brief Implementations to make periodic tasks and time operation more handy
 *
 *  @author Thomas Krueger
 *  @bug No known bugs.
 */
#include "posix_periodic.h"

double timespec2double (timespec time_to_convert)
{
  double time_double = double (time_to_convert.tv_sec) + (double) time_to_convert.tv_nsec  / 1000000000.0;
  printf("DEBUG: %s time_double = %f\n", __FUNCTION__, time_double);
  return time_double;
}

timespec Calc_Time_Diff(timespec start, timespec end)
{
	timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0) {
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	} else {
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}

int make_periodic (unsigned int period, struct periodic_info *info)
{
	int ret;
	unsigned int ns;
	unsigned int sec;
	int fd;
	struct itimerspec itval;

	/* Create the timer */
	fd = timerfd_create (CLOCK_REALTIME, 0);
	info->wakeups_missed = 0;
	info->timer_fd = fd;
	if (fd == -1)
		return fd;

	/* Make the timer periodic */
	sec = period/1000000;
	ns = (period - (sec * 1000000)) * 1000;
	itval.it_interval.tv_sec = sec;
	itval.it_interval.tv_nsec = ns;
	itval.it_value.tv_sec = sec;
	itval.it_value.tv_nsec = ns;
	ret = timerfd_settime (fd, 0, &itval, NULL);
	return ret;
}

void wait_period (struct periodic_info *info)
{
	unsigned long long missed;
	int ret;

	/* Wait for the next timer event. If we have missed any the
	   number is written to "missed" */
	ret = read (info->timer_fd, &missed, sizeof (missed));
	if (ret == -1)
	{
		perror ("read timer");
		return;
	}

	if (missed > 0)
	{
		info->wakeups_missed += (missed - 1);
	}
}<commit_msg>removed debug annotations<commit_after> /** @file posix_periodic.cpp
 *  @brief Implementations to make periodic tasks and time operation more handy
 *
 *  @author Thomas Krueger
 *  @bug No known bugs.
 */
#include "posix_periodic.h"

double timespec2double (timespec time_to_convert)
{
  double time_double = double (time_to_convert.tv_sec) + (double) time_to_convert.tv_nsec  / 1000000000.0;
  return time_double;
}

timespec Calc_Time_Diff(timespec start, timespec end)
{
	timespec temp;
	if ((end.tv_nsec-start.tv_nsec)<0) {
		temp.tv_sec = end.tv_sec-start.tv_sec-1;
		temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	} else {
		temp.tv_sec = end.tv_sec-start.tv_sec;
		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	}
	return temp;
}

int make_periodic (unsigned int period, struct periodic_info *info)
{
	int ret;
	unsigned int ns;
	unsigned int sec;
	int fd;
	struct itimerspec itval;

	/* Create the timer */
	fd = timerfd_create (CLOCK_REALTIME, 0);
	info->wakeups_missed = 0;
	info->timer_fd = fd;
	if (fd == -1)
		return fd;

	/* Make the timer periodic */
	sec = period/1000000;
	ns = (period - (sec * 1000000)) * 1000;
	itval.it_interval.tv_sec = sec;
	itval.it_interval.tv_nsec = ns;
	itval.it_value.tv_sec = sec;
	itval.it_value.tv_nsec = ns;
	ret = timerfd_settime (fd, 0, &itval, NULL);
	return ret;
}

void wait_period (struct periodic_info *info)
{
	unsigned long long missed;
	int ret;

	/* Wait for the next timer event. If we have missed any the
	   number is written to "missed" */
	ret = read (info->timer_fd, &missed, sizeof (missed));
	if (ret == -1)
	{
		perror ("read timer");
		return;
	}

	if (missed > 0)
	{
		info->wakeups_missed += (missed - 1);
	}
}<|endoftext|>