<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <cstdio>

#include "Compiler.hpp"

#include "Target.hpp"

#include "Utils.hpp"
#include "DebugStopWatch.hpp"
#include "Options.hpp"

#include "StringPool.hpp"
#include "FunctionTable.hpp"
#include "SemanticalException.hpp"
#include "AssemblyFileWriter.hpp"

#include "parser/SpiritParser.hpp"

#include "ast/SourceFile.hpp"
#include "ast/Position.hpp"

//Annotators
#include "ast/DefaultValues.hpp"
#include "ast/ContextAnnotator.hpp"
#include "ast/FunctionsAnnotator.hpp"
#include "ast/VariablesAnnotator.hpp"

//Checkers
#include "ast/StringChecker.hpp"
#include "ast/TypeChecker.hpp"

//Visitors
#include "ast/DependenciesResolver.hpp"
#include "ast/OptimizationEngine.hpp"
#include "ast/TransformerEngine.hpp"
#include "ast/WarningsEngine.hpp"
#include "ast/DebugVisitor.hpp"

//Three Address Code
#include "tac/Program.hpp"
#include "tac/Compiler.hpp"
#include "tac/BasicBlockExtractor.hpp"
#include "tac/TemporaryAllocator.hpp"
#include "tac/LivenessAnalyzer.hpp"
#include "tac/Optimizer.hpp"
#include "tac/Printer.hpp"

//Code generation
#include "asm/CodeGeneratorFactory.hpp"

//32 bits by default
eddic::Platform eddic::platform = Platform::INTEL_X86;

#ifdef DEBUG
static const bool debug = true;
#else
static const bool debug = false;
#endif

#define TIMER_START(name) StopWatch name_timer;
#define TIMER_END(name) if(debug){std::cout << #name << " took " << name_timer.elapsed() << "s" << std::endl;}

using namespace eddic;

void exec(const std::string& command);

int Compiler::compile(const std::string& file) {
    std::cout << "Compile " << file << std::endl;

    if(TargetDetermined && Target64){
        platform = Platform::INTEL_X86_64;
    }

    if(options.count("32")){
        platform = Platform::INTEL_X86;
    }

    if(options.count("64")){
        platform = Platform::INTEL_X86_64;
    }

    StopWatch timer;

    int code = compileOnly(file, platform);

    std::cout << "Compilation took " << timer.elapsed() << "s" << std::endl;

    return code;
}

void assemble(Platform platform, const std::string& output);
void assembleWithDebug(Platform platform, const std::string& output);

int Compiler::compileOnly(const std::string& file, Platform platform) {
    std::string output = options["output"].as<std::string>();

    int code = 0;
    try {
        TIMER_START(parsing)

        parser::SpiritParser parser;

        //The program to build
        ast::SourceFile program;

        //Parse the file into the program
        bool parsing = parser.parse(file, program);

        TIMER_END(parsing)

        if(parsing){
            //Symbol tables
            FunctionTable functionTable;
            StringPool pool;

            //Read dependencies
            includeDependencies(program, parser);

            //Apply some cleaning transformations
            clean(program);

            //Annotate the AST with more informations
            defineDefaultValues(program);

            //Fill the string pool
            checkStrings(program, pool);

            //Add some more informations to the AST
            defineContexts(program);
            defineVariables(program);
            defineFunctions(program, functionTable);

            //Transform the AST
            transform(program);

            //Static analysis
            checkTypes(program);

            //Check for warnings
            checkForWarnings(program, functionTable);

            //Check that there is a main in the program
            checkForMain(functionTable);

            //Optimize the AST
            optimize(program, functionTable, pool);

            tac::Program tacProgram;

            //Generate Three-Address-Code language
            tac::Compiler compiler;
            compiler.compile(program, pool, tacProgram);

            //Separate into basic blocks
            tac::BasicBlockExtractor extractor;
            extractor.extract(tacProgram);

            //Allocate storage for the temporaries that need to be stored
            tac::TemporaryAllocator allocator;
            allocator.allocate(tacProgram);

            tac::Optimizer optimizer;
            optimizer.optimize(tacProgram, pool);

            //Compute liveness of variables
            tac::LivenessAnalyzer liveness;
            liveness.compute(tacProgram);

            //Generate assembly from TAC
            AssemblyFileWriter writer("output.asm");

            as::CodeGeneratorFactory factory;
            auto generator = factory.get(platform, writer);
            generator->generate(tacProgram, pool, functionTable);
            writer.write();

            //If it's necessary, assemble and link the assembly
            if(!options.count("assembly")){
                if(options.count("debug")){
                    assembleWithDebug(platform, output);
                } else {
                    assemble(platform, output);
                }

                //Remove temporary files
                if(!options.count("keep")){
                    remove("output.asm");
                }

                remove("output.o");
            }
        }
    } catch (const SemanticalException& e) {
        if(e.position()){
            auto& position = *e.position();

            std::cout << position.file << ":" << position.line << ":" << " error: " << e.what() << std::endl;
        } else {
            std::cout << e.what() << std::endl;
        }

        code = 1;
    }

    return code;
}

void assemble(Platform platform, const std::string& output){
    switch(platform){
        case Platform::INTEL_X86:
            exec("nasm -f elf32 -o output.o output.asm");
            exec("ld -S -m elf_i386 output.o -o " + output);

            break;
        case Platform::INTEL_X86_64:
            exec("nasm -f elf64 -o output.o output.asm");
            exec("ld -S -m elf_x86_64 output.o -o " + output);

            break;
   }
}

void assembleWithDebug(Platform platform, const std::string& output){
    switch(platform){
        case Platform::INTEL_X86:
            exec("nasm -g -f elf32 -o output.o output.asm");
            exec("ld -m elf_i386 output.o -o " + output);

            break;
        case Platform::INTEL_X86_64:
            exec("nasm -g -f elf64 -o output.o output.asm");
            exec("ld -m elf_x86_64 output.o -o " + output);

        break;
   }
}

void eddic::defineDefaultValues(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate with default values");
    ast::DefaultValues values;
    values.fill(program);
}

void eddic::defineContexts(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate contexts");
    ast::ContextAnnotator annotator;
    annotator.annotate(program);
}

void eddic::defineVariables(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate variables");
    ast::VariablesAnnotator annotator;
    annotator.annotate(program);
}

void eddic::defineFunctions(ast::SourceFile& program, FunctionTable& functionTable){
    DebugStopWatch<debug> timer("Annotate functions");
    ast::FunctionsAnnotator annotator;
    annotator.annotate(program, functionTable);
}

void eddic::checkStrings(ast::SourceFile& program, StringPool& pool){
    DebugStopWatch<debug> timer("Strings checking");
    ast::StringChecker checker;
    checker.check(program, pool);
}

void eddic::checkTypes(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Types checking");
    ast::TypeChecker checker;
    checker.check(program);
}

void eddic::checkForWarnings(ast::SourceFile& program, FunctionTable& table){
    DebugStopWatch<debug> timer("Check for warnings");
    ast::WarningsEngine engine;
    engine.check(program, table);
}

void eddic::checkForMain(FunctionTable& table){
    if(!table.exists("main")){
        throw SemanticalException("Your program must contain a main function");
    }

    auto function = table.getFunction("main");

    if(function->parameters.size() > 1){
        throw SemanticalException("The signature of your main function is not valid");
    }

    if(function->parameters.size() == 1){
        auto type = function->parameters[0].paramType;

        if(type.base() != BaseType::STRING || !type.isArray()){
            throw SemanticalException("The signature of your main function is not valid");
        }
    }
}

void eddic::clean(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Cleaning");
    ast::TransformerEngine engine;
    engine.clean(program);
}

void eddic::transform(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Transformation");
    ast::TransformerEngine engine;
    engine.transform(program);
}

void eddic::optimize(ast::SourceFile& program, FunctionTable& functionTable, StringPool& pool){
    DebugStopWatch<debug> timer("Optimization");
    ast::OptimizationEngine engine;
    engine.optimize(program, functionTable, pool);
}

void eddic::includeDependencies(ast::SourceFile& sourceFile, parser::SpiritParser& parser){
    DebugStopWatch<debug> timer("Resolve dependencies");
    ast::DependenciesResolver resolver(parser);
    resolver.resolve(sourceFile);
}

void exec(const std::string& command) {
    DebugStopWatch<debug> timer("Exec " + command);

    if(debug){
        std::cout << "eddic : exec command : " << command << std::endl;
    }

    std::string result = execCommand(command);

    if(result.size() > 0){
        std::cout << result << std::endl;
    }
}

void eddic::warn(const std::string& warning){
    std::cout << "warning: " << warning << std::endl;
}

void eddic::warn(const eddic::ast::Position& position, const std::string& warning){
    std::cout << position.file << ":" << position.line << ": warning: " << warning << std::endl;
}
<commit_msg>Allow printing only tac or ast<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <cstdio>

#include "Compiler.hpp"

#include "Target.hpp"

#include "Utils.hpp"
#include "DebugStopWatch.hpp"
#include "Options.hpp"

#include "StringPool.hpp"
#include "FunctionTable.hpp"
#include "SemanticalException.hpp"
#include "AssemblyFileWriter.hpp"

#include "parser/SpiritParser.hpp"

#include "ast/SourceFile.hpp"
#include "ast/Position.hpp"

//Annotators
#include "ast/DefaultValues.hpp"
#include "ast/ContextAnnotator.hpp"
#include "ast/FunctionsAnnotator.hpp"
#include "ast/VariablesAnnotator.hpp"

//Checkers
#include "ast/StringChecker.hpp"
#include "ast/TypeChecker.hpp"

//Visitors
#include "ast/DependenciesResolver.hpp"
#include "ast/OptimizationEngine.hpp"
#include "ast/TransformerEngine.hpp"
#include "ast/WarningsEngine.hpp"
#include "ast/DebugVisitor.hpp"

//Three Address Code
#include "tac/Program.hpp"
#include "tac/Compiler.hpp"
#include "tac/BasicBlockExtractor.hpp"
#include "tac/TemporaryAllocator.hpp"
#include "tac/LivenessAnalyzer.hpp"
#include "tac/Optimizer.hpp"
#include "tac/Printer.hpp"

//Code generation
#include "asm/CodeGeneratorFactory.hpp"

//32 bits by default
eddic::Platform eddic::platform = Platform::INTEL_X86;

#ifdef DEBUG
static const bool debug = true;
#else
static const bool debug = false;
#endif

#define TIMER_START(name) StopWatch name_timer;
#define TIMER_END(name) if(debug){std::cout << #name << " took " << name_timer.elapsed() << "s" << std::endl;}

using namespace eddic;

void exec(const std::string& command);

int Compiler::compile(const std::string& file) {
    std::cout << "Compile " << file << std::endl;

    if(TargetDetermined && Target64){
        platform = Platform::INTEL_X86_64;
    }

    if(options.count("32")){
        platform = Platform::INTEL_X86;
    }

    if(options.count("64")){
        platform = Platform::INTEL_X86_64;
    }

    StopWatch timer;

    int code = compileOnly(file, platform);

    std::cout << "Compilation took " << timer.elapsed() << "s" << std::endl;

    return code;
}

void assemble(Platform platform, const std::string& output);
void assembleWithDebug(Platform platform, const std::string& output);

int Compiler::compileOnly(const std::string& file, Platform platform) {
    std::string output = options["output"].as<std::string>();

    int code = 0;
    try {
        TIMER_START(parsing)

        parser::SpiritParser parser;

        //The program to build
        ast::SourceFile program;

        //Parse the file into the program
        bool parsing = parser.parse(file, program);

        TIMER_END(parsing)

        //If the parsing was sucessfully
        if(parsing){
            //Symbol tables
            FunctionTable functionTable;
            StringPool pool;

            //Read dependencies
            includeDependencies(program, parser);

            //Apply some cleaning transformations
            clean(program);

            //Annotate the AST with more informations
            defineDefaultValues(program);

            //Fill the string pool
            checkStrings(program, pool);

            //Add some more informations to the AST
            defineContexts(program);
            defineVariables(program);
            defineFunctions(program, functionTable);

            //Transform the AST
            transform(program);

            //Static analysis
            checkTypes(program);

            //Check for warnings
            checkForWarnings(program, functionTable);

            //Check that there is a main in the program
            checkForMain(functionTable);

            //Optimize the AST
            optimize(program, functionTable, pool);

            //If the user asked for it, print the Abstract Syntax Tree
            if(options.count("ast") || options.count("ast-only")){
                ast::DebugVisitor()(program);
            }

            //If necessary, continue the compilation process
            if(!options.count("ast-only")){

                tac::Program tacProgram;

                //Generate Three-Address-Code language
                tac::Compiler compiler;
                compiler.compile(program, pool, tacProgram);

                //Separate into basic blocks
                tac::BasicBlockExtractor extractor;
                extractor.extract(tacProgram);

                //Allocate storage for the temporaries that need to be stored
                tac::TemporaryAllocator allocator;
                allocator.allocate(tacProgram);

                tac::Optimizer optimizer;
                optimizer.optimize(tacProgram, pool);

                //If asked by the user, print the Three Address code representation
                if(options.count("tac") || options.count("tac-only")){
                    tac::Printer printer;
                    printer.print(tacProgram);
                }

                //If necessary, continue the compilation process
                if(!options.count("tac-only")){
                    //Compute liveness of variables
                    tac::LivenessAnalyzer liveness;
                    liveness.compute(tacProgram);

                    //Generate assembly from TAC
                    AssemblyFileWriter writer("output.asm");

                    as::CodeGeneratorFactory factory;
                    auto generator = factory.get(platform, writer);
                    generator->generate(tacProgram, pool, functionTable);
                    writer.write();

                    //If it's necessary, assemble and link the assembly
                    if(!options.count("assembly")){
                        if(options.count("debug")){
                            assembleWithDebug(platform, output);
                        } else {
                            assemble(platform, output);
                        }

                        //Remove temporary files
                        if(!options.count("keep")){
                            remove("output.asm");
                        }

                        remove("output.o");
                    }
                }
            }
        }
    } catch (const SemanticalException& e) {
        if(e.position()){
            auto& position = *e.position();

            std::cout << position.file << ":" << position.line << ":" << " error: " << e.what() << std::endl;
        } else {
            std::cout << e.what() << std::endl;
        }

        code = 1;
    }

    return code;
}

void assemble(Platform platform, const std::string& output){
    switch(platform){
        case Platform::INTEL_X86:
            exec("nasm -f elf32 -o output.o output.asm");
            exec("ld -S -m elf_i386 output.o -o " + output);

            break;
        case Platform::INTEL_X86_64:
            exec("nasm -f elf64 -o output.o output.asm");
            exec("ld -S -m elf_x86_64 output.o -o " + output);

            break;
   }
}

void assembleWithDebug(Platform platform, const std::string& output){
    switch(platform){
        case Platform::INTEL_X86:
            exec("nasm -g -f elf32 -o output.o output.asm");
            exec("ld -m elf_i386 output.o -o " + output);

            break;
        case Platform::INTEL_X86_64:
            exec("nasm -g -f elf64 -o output.o output.asm");
            exec("ld -m elf_x86_64 output.o -o " + output);

        break;
   }
}

void eddic::defineDefaultValues(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate with default values");
    ast::DefaultValues values;
    values.fill(program);
}

void eddic::defineContexts(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate contexts");
    ast::ContextAnnotator annotator;
    annotator.annotate(program);
}

void eddic::defineVariables(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Annotate variables");
    ast::VariablesAnnotator annotator;
    annotator.annotate(program);
}

void eddic::defineFunctions(ast::SourceFile& program, FunctionTable& functionTable){
    DebugStopWatch<debug> timer("Annotate functions");
    ast::FunctionsAnnotator annotator;
    annotator.annotate(program, functionTable);
}

void eddic::checkStrings(ast::SourceFile& program, StringPool& pool){
    DebugStopWatch<debug> timer("Strings checking");
    ast::StringChecker checker;
    checker.check(program, pool);
}

void eddic::checkTypes(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Types checking");
    ast::TypeChecker checker;
    checker.check(program);
}

void eddic::checkForWarnings(ast::SourceFile& program, FunctionTable& table){
    DebugStopWatch<debug> timer("Check for warnings");
    ast::WarningsEngine engine;
    engine.check(program, table);
}

void eddic::checkForMain(FunctionTable& table){
    if(!table.exists("main")){
        throw SemanticalException("Your program must contain a main function");
    }

    auto function = table.getFunction("main");

    if(function->parameters.size() > 1){
        throw SemanticalException("The signature of your main function is not valid");
    }

    if(function->parameters.size() == 1){
        auto type = function->parameters[0].paramType;

        if(type.base() != BaseType::STRING || !type.isArray()){
            throw SemanticalException("The signature of your main function is not valid");
        }
    }
}

void eddic::clean(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Cleaning");
    ast::TransformerEngine engine;
    engine.clean(program);
}

void eddic::transform(ast::SourceFile& program){
    DebugStopWatch<debug> timer("Transformation");
    ast::TransformerEngine engine;
    engine.transform(program);
}

void eddic::optimize(ast::SourceFile& program, FunctionTable& functionTable, StringPool& pool){
    DebugStopWatch<debug> timer("Optimization");
    ast::OptimizationEngine engine;
    engine.optimize(program, functionTable, pool);
}

void eddic::includeDependencies(ast::SourceFile& sourceFile, parser::SpiritParser& parser){
    DebugStopWatch<debug> timer("Resolve dependencies");
    ast::DependenciesResolver resolver(parser);
    resolver.resolve(sourceFile);
}

void exec(const std::string& command) {
    DebugStopWatch<debug> timer("Exec " + command);

    if(debug){
        std::cout << "eddic : exec command : " << command << std::endl;
    }

    std::string result = execCommand(command);

    if(result.size() > 0){
        std::cout << result << std::endl;
    }
}

void eddic::warn(const std::string& warning){
    std::cout << "warning: " << warning << std::endl;
}

void eddic::warn(const eddic::ast::Position& position, const std::string& warning){
    std::cout << position.file << ":" << position.line << ": warning: " << warning << std::endl;
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * thrill/api/groupby.hpp
 *
 * DIANode for a groupby operation. Performs the actual groupby operation
 *
 * Part of Project Thrill - http://project-thrill.org
 *
 * Copyright (C) 2015 Huyen Chau Nguyen <hello@chau-nguyen.de>
 *
 * All rights reserved. Published under the BSD-2 license in the LICENSE file.
 ******************************************************************************/

#pragma once
#ifndef THRILL_API_GROUPBY_HEADER
#define THRILL_API_GROUPBY_HEADER

#include <thrill/api/dia.hpp>
#include <thrill/api/dop_node.hpp>
#include <thrill/api/groupby_iterator.hpp>
#include <thrill/common/functional.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/core/iterator_wrapper.hpp>
#include <thrill/core/multiway_merge.hpp>

#include <algorithm>
#include <functional>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <vector>

namespace thrill {
namespace api {

template <typename ValueType, typename ParentDIA,
          typename KeyExtractor, typename GroupFunction, typename HashFunction>
class GroupByNode final : public DOpNode<ValueType>
{
    static const bool debug = false;
    using Super = DOpNode<ValueType>;
    using Key = typename common::FunctionTraits<KeyExtractor>::result_type;
    using ValueOut = ValueType;
    using ValueIn = typename std::decay<typename common::FunctionTraits<KeyExtractor>
                                        ::template arg<0> >::type;

    using File = data::File;
    using Reader = typename File::Reader;
    using Writer = typename File::Writer;

    struct ValueComparator
    {
        explicit ValueComparator(const GroupByNode& info) : info_(info) { }
        const GroupByNode& info_;

        bool operator () (const ValueIn& i,
                          const ValueIn& j) {
            // REVIEW(ch): why is this a comparison by hash key? hash can have
            // collisions.
            auto i_cmp = info_.hash_function_(info_.key_extractor_(i));
            auto j_cmp = info_.hash_function_(info_.key_extractor_(j));
            return (i_cmp < j_cmp);
        }
    };

    using Super::context_;

public:
    /*!
     * Constructor for a GroupByNode. Sets the DataManager, parent, stack,
     * key_extractor and reduce_function.
     *
     * \param parent Parent DIA.
     * and this node
     * \param key_extractor Key extractor function
     * \param reduce_function Reduce function
     */
    GroupByNode(const ParentDIA& parent,
                const KeyExtractor& key_extractor,
                const GroupFunction& groupby_function,
                StatsNode* stats_node,
                const HashFunction& hash_function = HashFunction())
        : DOpNode<ValueType>(parent.ctx(), { parent.node() }, stats_node),
          key_extractor_(key_extractor),
          groupby_function_(groupby_function),
          hash_function_(hash_function)
    {
        // Hook PreOp
        auto pre_op_fn = [=](const ValueIn& input) {
                             PreOp(input);
                         };
        // close the function stack with our pre op and register it at
        // parent node for output
        auto lop_chain = parent.stack().push(pre_op_fn).emit();
        parent.node()->RegisterChild(lop_chain, this->type());
        stream_->OnClose([this]() {
                             this->WriteStreamStats(this->stream_);
                         });
    }

    /*!
     * Actually executes the reduce operation. Uses the member functions PreOp,
     * MainOp and PostOp.
     */
    void Execute() override {
        MainOp();
    }

    void PushData(bool consume) final {
        using Iterator = thrill::core::FileIteratorWrapper<ValueIn>;

        const size_t num_runs = files_.size();
        // if there's only one run, call user funcs
        if (num_runs == 1) {
            RunUserFunc(files_[0], consume);
        }       // otherwise sort all runs using multiway merge
        else {
            std::vector<std::pair<Iterator, Iterator> > seq;
            seq.reserve(num_runs);
            for (size_t t = 0; t < num_runs; ++t) {
                std::shared_ptr<Reader> reader = std::make_shared<Reader>(
                    files_[t].GetReader(consume));
                Iterator s = Iterator(&files_[t], reader, 0, true);
                Iterator e = Iterator(&files_[t], reader, files_[t].num_items(), false);
                seq.push_back(std::make_pair(std::move(s), std::move(e)));
            }

            auto puller = core::get_sequential_file_multiway_merge_tree<true, false>(
                seq.begin(),
                seq.end(),
                totalsize_,
                ValueComparator(*this));

            if (puller.HasNext()) {
                // create iterator to pass to user_function
                auto user_iterator = GroupByMultiwayMergeIterator<
                    ValueIn, KeyExtractor, ValueComparator>(puller, key_extractor_);
                while (user_iterator.HasNextForReal()) {
                    // call user function
                    const ValueOut res = groupby_function_(
                        user_iterator, user_iterator.GetNextKey());
                    // push result to callback functions
                    this->PushItem(res);
                }
            }
        }
    }

    void Dispose() override { }

private:
    const KeyExtractor& key_extractor_;
    const GroupFunction& groupby_function_;
    const HashFunction& hash_function_;

    data::CatStreamPtr stream_ { context_.GetNewCatStream() };
    std::vector<data::Stream::Writer> emitter_ { stream_->OpenWriters() };
    std::vector<data::File> files_;
    data::File sorted_elems_ { context_.GetFile() };
    size_t totalsize_ = 0;

    void RunUserFunc(File& f, bool consume) {
        auto r = f.GetReader(consume);
        if (r.HasNext()) {
            // create iterator to pass to user_function
            auto user_iterator = GroupByIterator<ValueIn, KeyExtractor, ValueComparator>(r, key_extractor_);
            while (user_iterator.HasNextForReal()) {
                // call user function
                const ValueOut res = groupby_function_(user_iterator,
                                                       user_iterator.GetNextKey());
                // push result to callback functions
                this->PushItem(res);
            }
        }
    }

    /*
     * Send all elements to their designated PEs
     */
    void PreOp(const ValueIn& v) {
        const Key k = key_extractor_(v);
        const auto recipient = hash_function_(k) % emitter_.size();
        emitter_[recipient](v);
    }

    /*
     * Sort and store elements in a file
     */
    void FlushVectorToFile(std::vector<ValueIn>& v) {
        totalsize_ += v.size();

        // sort run and sort to file
        std::sort(v.begin(), v.end(), ValueComparator(*this));
        File f = context_.GetFile();
        {
            Writer w = f.GetWriter();
            for (const ValueIn& e : v) {
                w(e);
            }
            w.Close();
        }

        files_.emplace_back(std::move(f));
    }

    //! Receive elements from other workers.
    auto MainOp() {
        LOG << "running group by main op";

        const size_t FIXED_VECTOR_SIZE = 1000000000 / sizeof(ValueIn);
        // const size_t FIXED_VECTOR_SIZE = 4;
        std::vector<ValueIn> incoming;
        incoming.reserve(FIXED_VECTOR_SIZE);

        // close all emitters
        for (auto& e : emitter_) {
            e.Close();
        }

        // get incoming elements
        auto reader = stream_->OpenCatReader(true /* consume */);
        while (reader.HasNext()) {
            // if vector is full save to disk
            if (incoming.size() == FIXED_VECTOR_SIZE) {
                FlushVectorToFile(incoming);
                incoming.clear();
            }
            // store incoming element
            incoming.emplace_back(reader.template Next<ValueIn>());
        }
        FlushVectorToFile(incoming);
        std::vector<ValueIn>().swap(incoming);

        stream_->Close();
    }
};

/******************************************************************************/

template <typename ValueType, typename Stack>
template <typename ValueOut,
          typename KeyExtractor,
          typename GroupFunction,
          typename HashFunction>
auto DIA<ValueType, Stack>::GroupBy(
    const KeyExtractor &key_extractor,
    const GroupFunction &groupby_function) const {

    using DOpResult = ValueOut;

    static_assert(
        std::is_same<
            typename std::decay<typename common::FunctionTraits<KeyExtractor>
                                ::template arg<0> >::type,
            ValueType>::value,
        "KeyExtractor has the wrong input type");

    StatsNode* stats_node = AddChildStatsNode("GroupBy", DIANodeType::DOP);
    using GroupByNode
              = api::GroupByNode<DOpResult, DIA, KeyExtractor,
                                 GroupFunction, HashFunction>;
    auto shared_node
        = std::make_shared<GroupByNode>(
        *this, key_extractor, groupby_function, stats_node);

    return DIA<DOpResult>(shared_node, { stats_node });
}

} // namespace api
} // namespace thrill

#endif // !THRILL_API_GROUPBY_HEADER

/******************************************************************************/
<commit_msg>GroupBy: applying fix that @sebalamm only applied to GroupByIndex, one week ago, fixes #101.<commit_after>/*******************************************************************************
 * thrill/api/groupby.hpp
 *
 * DIANode for a groupby operation. Performs the actual groupby operation
 *
 * Part of Project Thrill - http://project-thrill.org
 *
 * Copyright (C) 2015 Huyen Chau Nguyen <hello@chau-nguyen.de>
 *
 * All rights reserved. Published under the BSD-2 license in the LICENSE file.
 ******************************************************************************/

#pragma once
#ifndef THRILL_API_GROUPBY_HEADER
#define THRILL_API_GROUPBY_HEADER

#include <thrill/api/dia.hpp>
#include <thrill/api/dop_node.hpp>
#include <thrill/api/groupby_iterator.hpp>
#include <thrill/common/functional.hpp>
#include <thrill/common/logger.hpp>
#include <thrill/core/iterator_wrapper.hpp>
#include <thrill/core/multiway_merge.hpp>

#include <algorithm>
#include <functional>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <vector>

namespace thrill {
namespace api {

template <typename ValueType, typename ParentDIA,
          typename KeyExtractor, typename GroupFunction, typename HashFunction>
class GroupByNode final : public DOpNode<ValueType>
{
    static const bool debug = false;
    using Super = DOpNode<ValueType>;
    using Key = typename common::FunctionTraits<KeyExtractor>::result_type;
    using ValueOut = ValueType;
    using ValueIn = typename std::decay<typename common::FunctionTraits<KeyExtractor>
                                        ::template arg<0> >::type;

    using File = data::File;
    using Reader = typename File::Reader;
    using Writer = typename File::Writer;

    struct ValueComparator
    {
        explicit ValueComparator(const GroupByNode& info) : info_(info) { }
        const GroupByNode& info_;

        bool operator () (const ValueIn& i,
                          const ValueIn& j) {
            // REVIEW(ch): why is this a comparison by hash key? hash can have
            // collisions.
            auto i_cmp = info_.hash_function_(info_.key_extractor_(i));
            auto j_cmp = info_.hash_function_(info_.key_extractor_(j));
            return (i_cmp < j_cmp);
        }
    };

    using Super::context_;

public:
    /*!
     * Constructor for a GroupByNode. Sets the DataManager, parent, stack,
     * key_extractor and reduce_function.
     *
     * \param parent Parent DIA.
     * and this node
     * \param key_extractor Key extractor function
     * \param reduce_function Reduce function
     */
    GroupByNode(const ParentDIA& parent,
                const KeyExtractor& key_extractor,
                const GroupFunction& groupby_function,
                StatsNode* stats_node,
                const HashFunction& hash_function = HashFunction())
        : DOpNode<ValueType>(parent.ctx(), { parent.node() }, stats_node),
          key_extractor_(key_extractor),
          groupby_function_(groupby_function),
          hash_function_(hash_function)
    {
        // Hook PreOp
        auto pre_op_fn = [=](const ValueIn& input) {
                             PreOp(input);
                         };
        // close the function stack with our pre op and register it at
        // parent node for output
        auto lop_chain = parent.stack().push(pre_op_fn).emit();
        parent.node()->RegisterChild(lop_chain, this->type());
        stream_->OnClose([this]() {
                             this->WriteStreamStats(this->stream_);
                         });
    }

    /*!
     * Actually executes the reduce operation. Uses the member functions PreOp,
     * MainOp and PostOp.
     */
    void Execute() override {
        MainOp();
    }

    void PushData(bool consume) final {
        using Iterator = thrill::core::FileIteratorWrapper<ValueIn>;

        const size_t num_runs = files_.size();
        // if there's only one run, call user funcs
        if (num_runs == 1) {
            RunUserFunc(files_[0], consume);
        }       // otherwise sort all runs using multiway merge
        else {
            std::vector<std::pair<Iterator, Iterator> > seq;
            seq.reserve(num_runs);
            for (size_t t = 0; t < num_runs; ++t) {
                std::shared_ptr<Reader> reader = std::make_shared<Reader>(
                    files_[t].GetReader(consume));
                Iterator s = Iterator(&files_[t], reader, 0, true);
                Iterator e = Iterator(&files_[t], reader, files_[t].num_items(), false);
                seq.push_back(std::make_pair(std::move(s), std::move(e)));
            }

            auto puller = core::get_sequential_file_multiway_merge_tree<true, false>(
                seq.begin(),
                seq.end(),
                totalsize_,
                ValueComparator(*this));

            if (puller.HasNext()) {
                // create iterator to pass to user_function
                auto user_iterator = GroupByMultiwayMergeIterator<
                    ValueIn, KeyExtractor, ValueComparator>(puller, key_extractor_);
                while (user_iterator.HasNextForReal()) {
                    // call user function
                    const ValueOut res = groupby_function_(
                        user_iterator, user_iterator.GetNextKey());
                    // push result to callback functions
                    this->PushItem(res);
                }
            }
        }
    }

    void Dispose() override { }

private:
    KeyExtractor key_extractor_;
    GroupFunction groupby_function_;
    HashFunction hash_function_;

    data::CatStreamPtr stream_ { context_.GetNewCatStream() };
    std::vector<data::Stream::Writer> emitter_ { stream_->OpenWriters() };
    std::vector<data::File> files_;
    data::File sorted_elems_ { context_.GetFile() };
    size_t totalsize_ = 0;

    void RunUserFunc(File& f, bool consume) {
        auto r = f.GetReader(consume);
        if (r.HasNext()) {
            // create iterator to pass to user_function
            auto user_iterator = GroupByIterator<ValueIn, KeyExtractor, ValueComparator>(r, key_extractor_);
            while (user_iterator.HasNextForReal()) {
                // call user function
                const ValueOut res = groupby_function_(user_iterator,
                                                       user_iterator.GetNextKey());
                // push result to callback functions
                this->PushItem(res);
            }
        }
    }

    /*
     * Send all elements to their designated PEs
     */
    void PreOp(const ValueIn& v) {
        const Key k = key_extractor_(v);
        const auto recipient = hash_function_(k) % emitter_.size();
        emitter_[recipient](v);
    }

    /*
     * Sort and store elements in a file
     */
    void FlushVectorToFile(std::vector<ValueIn>& v) {
        totalsize_ += v.size();

        // sort run and sort to file
        std::sort(v.begin(), v.end(), ValueComparator(*this));
        File f = context_.GetFile();
        {
            Writer w = f.GetWriter();
            for (const ValueIn& e : v) {
                w(e);
            }
            w.Close();
        }

        files_.emplace_back(std::move(f));
    }

    //! Receive elements from other workers.
    auto MainOp() {
        LOG << "running group by main op";

        const size_t FIXED_VECTOR_SIZE = 1000000000 / sizeof(ValueIn);
        // const size_t FIXED_VECTOR_SIZE = 4;
        std::vector<ValueIn> incoming;
        incoming.reserve(FIXED_VECTOR_SIZE);

        // close all emitters
        for (auto& e : emitter_) {
            e.Close();
        }

        // get incoming elements
        auto reader = stream_->OpenCatReader(true /* consume */);
        while (reader.HasNext()) {
            // if vector is full save to disk
            if (incoming.size() == FIXED_VECTOR_SIZE) {
                FlushVectorToFile(incoming);
                incoming.clear();
            }
            // store incoming element
            incoming.emplace_back(reader.template Next<ValueIn>());
        }
        FlushVectorToFile(incoming);
        std::vector<ValueIn>().swap(incoming);

        stream_->Close();
    }
};

/******************************************************************************/

template <typename ValueType, typename Stack>
template <typename ValueOut,
          typename KeyExtractor,
          typename GroupFunction,
          typename HashFunction>
auto DIA<ValueType, Stack>::GroupBy(
    const KeyExtractor &key_extractor,
    const GroupFunction &groupby_function) const {

    using DOpResult = ValueOut;

    static_assert(
        std::is_same<
            typename std::decay<typename common::FunctionTraits<KeyExtractor>
                                ::template arg<0> >::type,
            ValueType>::value,
        "KeyExtractor has the wrong input type");

    StatsNode* stats_node = AddChildStatsNode("GroupBy", DIANodeType::DOP);
    using GroupByNode
              = api::GroupByNode<DOpResult, DIA, KeyExtractor,
                                 GroupFunction, HashFunction>;
    auto shared_node
        = std::make_shared<GroupByNode>(
        *this, key_extractor, groupby_function, stats_node);

    return DIA<DOpResult>(shared_node, { stats_node });
}

} // namespace api
} // namespace thrill

#endif // !THRILL_API_GROUPBY_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>/*
 * File:   AddressesPage.cpp
 * Author: danny
 *
 * Created on February 16, 2015, 12:26 PM
 */

#include "AddressesPage.h"
#include "DataSubsystem.h"
#include "WebMenu.h"
#include "EditThingPage.h"
#include <Poco/Data/Session.h>
#include <Poco/Util/Application.h>

const std::string AddressesPage::Title("My Addresses");
const std::string AddressesPage::Link("addresses.bin");

AddressesPage::AddressesPage()
{
}

AddressesPage::~AddressesPage()
{
}

std::string AddressesPage::title() const
{
    return Title;
}

bool AddressesPage::handleForm(Poco::Net::HTMLForm& form, Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
    return false;
}

void AddressesPage::renderPanelBody(std::ostream& output, Poco::Net::HTTPServerRequest& request)
{
    renderTable(output);

    renderScripts(output);
}

void AddressesPage::renderButtons(std::ostream& output)
{

}

std::string AddressesPage::subtitle() const
{
    return "Some text goes here";
}

void AddressesPage::renderTable(std::ostream& output)
{
    output << "
";
    output << "
";
    output << "
";
    output << "
";
    output << "            MAC	";
    output << "            IP	";
    output << "            Last	";
    output << "            Type	";
    output << "            Name	";
    output << "            Vendor	";
    output << "            OS	";
    output << "            Description	";
    output << "            HW	";
    output << "            Authorized	";
    output << "
";
    output << "
";

    output << "
";

    Poco::Data::Session session = Poco::Util::Application::instance().getSubsystem<DataSubsystem>().createSession();
    Poco::Data::Statement query(session);
    query << "SELECT ip.mac, ip, datetime(last_seen,'unixepoch','localtime') as last_seen, "
            "thing.id, thing.type, thing.name, thing.vendor, "
            "thing.os, desc, oui.vendor as hw_vendor , case when  authorized.mac is null then 'no' else 'yes' end as auth "
            "FROM ip LEFT JOIN thing ON ip.thingid=thing.id "
            "LEFT JOIN oui ON substr(ip.mac,0,9)=oui.prefix "
            "LEFT JOIN authorized on ip.mac=authorized.mac "
            "ORDER BY ip.mac";
    query.execute();
    Poco::Data::RecordSet rs(query);
    bool more = rs.moveFirst();
    while (more) {
        renderRow(output, rs);
        more = rs.moveNext();
    }
    output << "
";
    output << "
";
}

void AddressesPage::renderRow(std::ostream& output, Poco::Data::RecordSet& rs)
{
    output << "
";
    for (size_t i = 0; i < rs.columnCount(); ++i) {
        if (rs.columnName(i) == "id") {
            continue;
        }
        output << "";
        if (!rs[i].isEmpty()) {
            if (rs.columnName(i) == "mac") {
                output << Poco::format("", EditThingPage::Link, rs["id"].toString());
            }
            output << rs[i].toString();
            if (rs.columnName(i) == "mac") {
                output << "";
            }
        }
        output << "	";
    }
    output << "
";
}

void AddressesPage::renderScripts(std::ostream& output)
{
    output << "";

}

<commit_msg>#26: Rename column headers in the "My Addresses" screen<commit_after>/*
 * File:   AddressesPage.cpp
 * Author: danny
 *
 * Created on February 16, 2015, 12:26 PM
 */

#include "AddressesPage.h"
#include "DataSubsystem.h"
#include "WebMenu.h"
#include "EditThingPage.h"
#include <Poco/Data/Session.h>
#include <Poco/Util/Application.h>

const std::string AddressesPage::Title("My Addresses");
const std::string AddressesPage::Link("addresses.bin");

AddressesPage::AddressesPage()
{
}

AddressesPage::~AddressesPage()
{
}

std::string AddressesPage::title() const
{
    return Title;
}

bool AddressesPage::handleForm(Poco::Net::HTMLForm& form, Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
    return false;
}

void AddressesPage::renderPanelBody(std::ostream& output, Poco::Net::HTTPServerRequest& request)
{
    renderTable(output);

    renderScripts(output);
}

void AddressesPage::renderButtons(std::ostream& output)
{

}

std::string AddressesPage::subtitle() const
{
    return "Some text goes here";
}

void AddressesPage::renderTable(std::ostream& output)
{
    output << "
";
    output << "
";
    output << "
";
    output << "
";
    output << "            MAC Address	";
    output << "            IP Address	";
    output << "            Last Seen	";
    output << "            Type	";
    output << "            Name	";
    output << "            Vendor	";
    output << "            Operating System	";
    output << "            Description	";
    output << "            Hardware Family	";
    output << "            Authorized	";
    output << "
";
    output << "
";

    output << "
";

    Poco::Data::Session session = Poco::Util::Application::instance().getSubsystem<DataSubsystem>().createSession();
    Poco::Data::Statement query(session);
    query << "SELECT ip.mac, ip, datetime(last_seen,'unixepoch','localtime') as last_seen, "
            "thing.id, thing.type, thing.name, thing.vendor, "
            "thing.os, desc, oui.vendor as hw_vendor , case when  authorized.mac is null then 'no' else 'yes' end as auth "
            "FROM ip LEFT JOIN thing ON ip.thingid=thing.id "
            "LEFT JOIN oui ON substr(ip.mac,0,9)=oui.prefix "
            "LEFT JOIN authorized on ip.mac=authorized.mac "
            "ORDER BY ip.mac";
    query.execute();
    Poco::Data::RecordSet rs(query);
    bool more = rs.moveFirst();
    while (more) {
        renderRow(output, rs);
        more = rs.moveNext();
    }
    output << "
";
    output << "
";
}

void AddressesPage::renderRow(std::ostream& output, Poco::Data::RecordSet& rs)
{
    output << "
";
    for (size_t i = 0; i < rs.columnCount(); ++i) {
        if (rs.columnName(i) == "id") {
            continue;
        }
        output << "";
        if (!rs[i].isEmpty()) {
            if (rs.columnName(i) == "mac") {
                output << Poco::format("", EditThingPage::Link, rs["id"].toString());
            }
            output << rs[i].toString();
            if (rs.columnName(i) == "mac") {
                output << "";
            }
        }
        output << "	";
    }
    output << "
";
}

void AddressesPage::renderScripts(std::ostream& output)
{
    output << "";

}

<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(c)

class Solution {
public:
    /**
     * @param A: A string includes Upper Case letters
     * @param B: A string includes Upper Case letter
     * @return:  if string A contains all of the characters in B return true
     *           else return false
     */
    bool compareStrings(string A, string B) {
        // write your code here
        unordered_map<char, size_t> h;
        for (auto& c: B) {
            ++h[c];
        }

        size_t cnt = B.length();
        for (auto& c: A) {
            if (h[c] > 0) {
                --h[c];
                --cnt;
            }
            if (cnt == 0) {
                return true;
            }
        }

        if (cnt > 0) {
            return false;
        }

        return true;
    }
};

<commit_msg>Update compare-strings.cpp<commit_after>// Time:  O(n)
// Space: O(c)

class Solution {
public:
    /**
     * @param A: A string includes Upper Case letters
     * @param B: A string includes Upper Case letter
     * @return:  if string A contains all of the characters in B return true
     *           else return false
     */
    bool compareStrings(string A, string B) {
        unordered_map<char, int> h;
        for (auto& c: A) {
            ++h[c];
        }

        for (auto& c: B) {
            if (--h[c] < 0) {
                return false;
            }
        }

        return true;
    }
};

class Solution2 {
public:
    /**
     * @param A: A string includes Upper Case letters
     * @param B: A string includes Upper Case letter
     * @return:  if string A contains all of the characters in B return true
     *           else return false
     */
    bool compareStrings(string A, string B) {
        // write your code here
        unordered_map<char, int> h;
        for (auto& c: B) {
            ++h[c];
        }

        size_t cnt = B.length();
        for (auto& c: A) {
            if (h[c] > 0) {
                --h[c];
                --cnt;
            }
            if (cnt == 0) {
                return true;
            }
        }

        if (cnt > 0) {
            return false;
        }

        return true;
    }
};

<|endoftext|>


<commit_before>// Time:  O(n * n!)
// Space: O(n)

class Solution {
public:
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    vector<vector<int>> permuteUnique(vector<int> &nums) {
        vector<vector<int>> result;
        deque<bool> used(nums.size(), false);
        vector<int> ans;

        sort(nums.begin(), nums.end());
        permuteUniqueRecu(nums, &used, &ans, &result);
        return result;
    }

    void permuteUniqueRecu(const vector<int> &A, deque<bool> *used,
                                    vector<int> *ans, vector<vector<int>> *result) {
        if (ans->size() == A.size()) {
            result->emplace_back(*ans);
            return;
        }

        for (size_t i = 0; i < A.size(); ++i) {
            if (!(*used)[i] && !(i != 0 && A[i - 1] == A[i] && (*used)[i - 1])) {
                (*used)[i] = true;
                ans->emplace_back(A[i]);
                permuteUniqueRecu(A, used, ans, result);
                ans->pop_back();
                (*used)[i] = false;
            }
        }
    }
};
<commit_msg>Update permutations-ii.cpp<commit_after>// Time:  O(n * n!)
// Space: O(n)

class Solution {
public:
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    vector<vector<int>> permuteUnique(vector<int> &nums) {
        vector<vector<int>> result;
        deque<bool> used(nums.size(), false);
        vector<int> ans;

        sort(nums.begin(), nums.end());
        permuteUniqueRecu(nums, &used, &ans, &result);
        return result;
    }

    void permuteUniqueRecu(const vector<int> &A, deque<bool> *used,
                           vector<int> *ans, vector<vector<int>> *result) {
        if (ans->size() == A.size()) {
            result->emplace_back(*ans);
            return;
        }

        for (size_t i = 0; i < A.size(); ++i) {
            if (!(*used)[i] && !(i != 0 && A[i - 1] == A[i] && (*used)[i - 1])) {
                (*used)[i] = true;
                ans->emplace_back(A[i]);
                permuteUniqueRecu(A, used, ans, result);
                ans->pop_back();
                (*used)[i] = false;
            }
        }
    }
};
<|endoftext|>


<commit_before>#include "Database.h"

#include "Task.h"

#include <assert.h>
#include <sstream>

int Database::_count = 0;

Database::Database(Task* task) {
	++_count;

	_task = task;

	v8::Handle<v8::External> data = v8::External::New(task->getIsolate(), this);

	v8::Local<v8::ObjectTemplate> databaseTemplate = v8::ObjectTemplate::New(task->getIsolate());
	databaseTemplate->SetInternalFieldCount(1);
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "get"), v8::FunctionTemplate::New(task->getIsolate(), get, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "set"), v8::FunctionTemplate::New(task->getIsolate(), set, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "remove"), v8::FunctionTemplate::New(task->getIsolate(), remove, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "getAll"), v8::FunctionTemplate::New(task->getIsolate(), getAll, data));

	v8::Local<v8::Object> databaseObject = databaseTemplate->NewInstance();
	databaseObject->SetInternalField(0, v8::External::New(task->getIsolate(), this));
	_object = v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >(task->getIsolate(), databaseObject);
}

Database::~Database() {
	--_count;
}

void Database::create(const v8::FunctionCallbackInfo<v8::Value>& args) {
	v8::HandleScope handleScope(args.GetIsolate());
	if (Database* database = new Database(Task::get(args.GetIsolate()))) {
		if (database->open(args.GetIsolate(), *v8::String::Utf8Value(args[0].As<v8::String>()))) {
			v8::Handle<v8::Object> result = v8::Local<v8::Object>::New(args.GetIsolate(), database->_object);
			args.GetReturnValue().Set(result);
		}
		database->release();
	}
}

bool Database::checkError(const char* command, int result) {
	bool isError = false;
	if (result != MDB_SUCCESS) {
		isError = true;

		std::ostringstream buffer;
		buffer << command << " failed (" << result << "): " << mdb_strerror(result);
		_task->getIsolate()->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(_task->getIsolate(), buffer.str().c_str())));
	}
	return isError;
}

bool Database::open(v8::Isolate* isolate, const char* path) {
	int result = mdb_env_create(&_environment);
	if (checkError("mdb_env_create", result)) {
		return false;
	}

	result = mdb_env_set_maxdbs(_environment, 10);
	checkError("mdb_env_set_maxdbs", result);

	result = mdb_env_open(_environment, path, 0, 0644);
	if (!checkError("mdb_env_open", result)) {
		result = mdb_txn_begin(_environment, 0, 0, &_transaction);
		if (!checkError("mdb_txn_begin", result)) {
			result = mdb_dbi_open(_transaction, path, MDB_CREATE, &_database);
			if (!checkError("mdb_dbi_open", result)) {
				result = mdb_txn_commit(_transaction);
				checkError("mdb_txn_commit", result);
			}
		}

		if (result != MDB_SUCCESS) {
			mdb_txn_abort(_transaction);
		}
	}

	if (result != MDB_SUCCESS) {
		mdb_env_close(_environment);
	}

	return result == MDB_SUCCESS;
}

void Database::get(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, MDB_RDONLY, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			MDB_val value;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			if (mdb_get(database->_transaction, database->_database, &key, &value) == MDB_SUCCESS) {
				args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), reinterpret_cast<const char*>(value.mv_data), v8::String::kNormalString, value.mv_size));
			}
			mdb_txn_reset(database->_transaction);
		}
	}
}

void Database::set(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, 0, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			MDB_val data;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			v8::String::Utf8Value valueString(args[1]->ToString(args.GetIsolate()));
			data.mv_data = *valueString;
			data.mv_size = valueString.length();
			result = mdb_put(database->_transaction, database->_database, &key, &data, 0);
			database->checkError("mdb_put", result);
			mdb_txn_commit(database->_transaction);
		}
	}
}

void Database::remove(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, 0, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			result = mdb_del(database->_transaction, database->_database, &key, 0);
			database->checkError("mdb_del", result);
			mdb_txn_commit(database->_transaction);
		}
	}
}

void Database::getAll(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, MDB_RDONLY, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_cursor* cursor;
			result = mdb_cursor_open(database->_transaction, database->_database, &cursor);
			if (!database->checkError("mdb_cursor_open", result)) {
				int expectedCount = 0;
				MDB_stat statistics;
				if (mdb_stat(database->_transaction, database->_database, &statistics) == 0) {
					expectedCount = statistics.ms_entries;
				}
				v8::Local<v8::Array> array = v8::Array::New(args.GetIsolate(), expectedCount);

				MDB_val key;
				int index = 0;
				while ((result = mdb_cursor_get(cursor, &key, 0, MDB_NEXT)) == 0) {
					array->Set(index++, v8::String::NewFromUtf8(args.GetIsolate(), reinterpret_cast<const char*>(key.mv_data), v8::String::kNormalString, key.mv_size));
				}
				if (result == MDB_NOTFOUND) {
					args.GetReturnValue().Set(array);
				} else {
					database->checkError("mdb_cursor_get", result);
				}
				mdb_cursor_close(cursor);
			}
			mdb_txn_reset(database->_transaction);
		}
	}
}

void Database::onRelease(const v8::WeakCallbackData<v8::Object, Database>& data) {
	data.GetParameter()->_object.Reset();
	delete data.GetParameter();
}

void Database::ref() {
	if (++_refCount == 1) {
		_object.ClearWeak();
	}
}

void Database::release() {
	assert(_refCount >= 1);
	if (--_refCount == 0) {
		_object.SetWeak(this, onRelease);
	}
}

Database* Database::get(v8::Handle<v8::Value> databaseObject) {
	return reinterpret_cast<Database*>(v8::Handle<v8::External>::Cast(databaseObject)->Value());
}
<commit_msg>Augh.  My databases had their paths baked in them.<commit_after>#include "Database.h"

#include "Task.h"

#include <assert.h>
#include <sstream>

int Database::_count = 0;

Database::Database(Task* task) {
	++_count;

	_task = task;

	v8::Handle<v8::External> data = v8::External::New(task->getIsolate(), this);

	v8::Local<v8::ObjectTemplate> databaseTemplate = v8::ObjectTemplate::New(task->getIsolate());
	databaseTemplate->SetInternalFieldCount(1);
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "get"), v8::FunctionTemplate::New(task->getIsolate(), get, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "set"), v8::FunctionTemplate::New(task->getIsolate(), set, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "remove"), v8::FunctionTemplate::New(task->getIsolate(), remove, data));
	databaseTemplate->Set(v8::String::NewFromUtf8(task->getIsolate(), "getAll"), v8::FunctionTemplate::New(task->getIsolate(), getAll, data));

	v8::Local<v8::Object> databaseObject = databaseTemplate->NewInstance();
	databaseObject->SetInternalField(0, v8::External::New(task->getIsolate(), this));
	_object = v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >(task->getIsolate(), databaseObject);
}

Database::~Database() {
	--_count;
}

void Database::create(const v8::FunctionCallbackInfo<v8::Value>& args) {
	v8::HandleScope handleScope(args.GetIsolate());
	if (Database* database = new Database(Task::get(args.GetIsolate()))) {
		if (database->open(args.GetIsolate(), *v8::String::Utf8Value(args[0].As<v8::String>()))) {
			v8::Handle<v8::Object> result = v8::Local<v8::Object>::New(args.GetIsolate(), database->_object);
			args.GetReturnValue().Set(result);
		}
		database->release();
	}
}

bool Database::checkError(const char* command, int result) {
	bool isError = false;
	if (result != MDB_SUCCESS) {
		isError = true;

		std::ostringstream buffer;
		buffer << command << " failed (" << result << "): " << mdb_strerror(result);
		_task->getIsolate()->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(_task->getIsolate(), buffer.str().c_str())));
	}
	return isError;
}

bool Database::open(v8::Isolate* isolate, const char* path) {
	int result = mdb_env_create(&_environment);
	if (checkError("mdb_env_create", result)) {
		return false;
	}

	result = mdb_env_set_maxdbs(_environment, 10);
	checkError("mdb_env_set_maxdbs", result);

	result = mdb_env_open(_environment, path, 0, 0644);
	if (!checkError("mdb_env_open", result)) {
		result = mdb_txn_begin(_environment, 0, 0, &_transaction);
		if (!checkError("mdb_txn_begin", result)) {
			result = mdb_dbi_open(_transaction, NULL, MDB_CREATE, &_database);
			if (!checkError("mdb_dbi_open", result)) {
				result = mdb_txn_commit(_transaction);
				checkError("mdb_txn_commit", result);
			}
		}

		if (result != MDB_SUCCESS) {
			mdb_txn_abort(_transaction);
		}
	}

	if (result != MDB_SUCCESS) {
		mdb_env_close(_environment);
	}

	return result == MDB_SUCCESS;
}

void Database::get(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, MDB_RDONLY, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			MDB_val value;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			if (mdb_get(database->_transaction, database->_database, &key, &value) == MDB_SUCCESS) {
				args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), reinterpret_cast<const char*>(value.mv_data), v8::String::kNormalString, value.mv_size));
			}
			mdb_txn_reset(database->_transaction);
		}
	}
}

void Database::set(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, 0, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			MDB_val data;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			v8::String::Utf8Value valueString(args[1]->ToString(args.GetIsolate()));
			data.mv_data = *valueString;
			data.mv_size = valueString.length();
			result = mdb_put(database->_transaction, database->_database, &key, &data, 0);
			database->checkError("mdb_put", result);
			mdb_txn_commit(database->_transaction);
		}
	}
}

void Database::remove(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, 0, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_val key;
			v8::String::Utf8Value keyString(args[0].As<v8::String>());
			key.mv_data = *keyString;
			key.mv_size = keyString.length();
			result = mdb_del(database->_transaction, database->_database, &key, 0);
			database->checkError("mdb_del", result);
			mdb_txn_commit(database->_transaction);
		}
	}
}

void Database::getAll(const v8::FunctionCallbackInfo<v8::Value>& args) {
	if (Database* database = Database::get(args.Data())) {
		int result = mdb_txn_begin(database->_environment, 0, MDB_RDONLY, &database->_transaction);
		if (!database->checkError("mdb_txn_begin", result)) {
			MDB_cursor* cursor;
			result = mdb_cursor_open(database->_transaction, database->_database, &cursor);
			if (!database->checkError("mdb_cursor_open", result)) {
				int expectedCount = 0;
				MDB_stat statistics;
				if (mdb_stat(database->_transaction, database->_database, &statistics) == 0) {
					expectedCount = statistics.ms_entries;
				}
				v8::Local<v8::Array> array = v8::Array::New(args.GetIsolate(), expectedCount);

				MDB_val key;
				int index = 0;
				while ((result = mdb_cursor_get(cursor, &key, 0, MDB_NEXT)) == 0) {
					array->Set(index++, v8::String::NewFromUtf8(args.GetIsolate(), reinterpret_cast<const char*>(key.mv_data), v8::String::kNormalString, key.mv_size));
				}
				if (result == MDB_NOTFOUND) {
					args.GetReturnValue().Set(array);
				} else {
					database->checkError("mdb_cursor_get", result);
				}
				mdb_cursor_close(cursor);
			}
			mdb_txn_reset(database->_transaction);
		}
	}
}

void Database::onRelease(const v8::WeakCallbackData<v8::Object, Database>& data) {
	data.GetParameter()->_object.Reset();
	delete data.GetParameter();
}

void Database::ref() {
	if (++_refCount == 1) {
		_object.ClearWeak();
	}
}

void Database::release() {
	assert(_refCount >= 1);
	if (--_refCount == 0) {
		_object.SetWeak(this, onRelease);
	}
}

Database* Database::get(v8::Handle<v8::Value> databaseObject) {
	return reinterpret_cast<Database*>(v8::Handle<v8::External>::Cast(databaseObject)->Value());
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRectilinearGridGeometryFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkRectilinearGridGeometryFilter.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkRectilinearGrid.h"

vtkStandardNewMacro(vtkRectilinearGridGeometryFilter);

// Construct with initial extent (0,100, 0,100, 0,0) (i.e., a k-plane).
vtkRectilinearGridGeometryFilter::vtkRectilinearGridGeometryFilter()
{
  this->Extent[0] = 0;
  this->Extent[1] = VTK_LARGE_INTEGER;
  this->Extent[2] = 0;
  this->Extent[3] = VTK_LARGE_INTEGER;
  this->Extent[4] = 0;
  this->Extent[5] = VTK_LARGE_INTEGER;
}

int vtkRectilinearGridGeometryFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkRectilinearGrid *input = vtkRectilinearGrid::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  int *dims, dimension, dir[3], diff[3];
  int i, j, k, extent[6];
  vtkIdType idx, startIdx, startCellIdx;
  vtkIdType ptIds[4];
  vtkIdType cellId;
  vtkPoints *newPts=0;
  vtkCellArray *newVerts=0;
  vtkCellArray *newLines=0;
  vtkCellArray *newPolys=0;
  vtkIdType totPoints, pos;
  int offset[3], numPolys;
  double x[3];
  vtkPointData *pd, *outPD;
  vtkCellData *cd, *outCD;

  vtkDebugMacro(<< "Extracting rectilinear points geometry");

  pd = input->GetPointData();
  outPD = output->GetPointData();
  outPD->CopyNormalsOff();
  cd = input->GetCellData();
  outCD = output->GetCellData();
  dims = input->GetDimensions();
  //
  // Based on the dimensions of the rectilinear data,
  // and the extent of the geometry,
  // compute the combined extent plus the dimensionality of the data
  //
  for (dimension=3, i=0; i<3; i++)
    {
    extent[2*i] = this->Extent[2*i] < 0 ? 0 : this->Extent[2*i];
    extent[2*i] = this->Extent[2*i] >= dims[i] ? dims[i]-1 : this->Extent[2*i];
    extent[2*i+1] = this->Extent[2*i+1] >= dims[i] ? dims[i]-1 : this->Extent[2*i+1];
    if ( extent[2*i+1] < extent[2*i] )
      {
      extent[2*i+1] = extent[2*i];
      }
    if ( (extent[2*i+1] - extent[2*i]) == 0 )
      {
      dimension--;
      }
    }
  //
  // Now create polygonal data based on dimension of data
  //
  startIdx = extent[0] + extent[2]*dims[0] + extent[4]*dims[0]*dims[1];
  // The cell index is a bit more complicated at the boundaries
  if (dims[0] == 1)
    {
    startCellIdx = extent[0];
    }
  else
    {
    startCellIdx =  (extent[0] < dims[0] - 1) ? extent[0]
                                              : extent[0]-1;
    }
  if (dims[1] == 1)
    {
    startCellIdx += extent[2]*(dims[0]-1);
    }
  else
    {
    startCellIdx += (extent[2] < dims[1] - 1) ? extent[2]*(dims[0]-1)
                                              : (extent[2]-1)*(dims[0]-1);
    }
  if (dims[2] == 1)
    {
    startCellIdx += extent[4]*(dims[0]-1)*(dims[1]-1);
    }
  else
    {
    startCellIdx += (extent[4] < dims[2] - 1) ? extent[4]*(dims[0]-1)*(dims[1]-1)
                                              : (extent[4]-1)*(dims[0]-1)*(dims[1]-1);
    }

  switch (dimension)
    {
    default:
      break;

    case 0: // --------------------- build point -----------------------

      newPts = vtkPoints::New();
      newPts->Allocate(1);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(1,1));
      outPD->CopyAllocate(pd,1);
      outCD->CopyAllocate(cd,1);

      ptIds[0] = newPts->InsertNextPoint(input->GetPoint(startIdx));
      outPD->CopyData(pd,startIdx,ptIds[0]);

      cellId = newVerts->InsertNextCell(1,ptIds);
      outCD->CopyData(cd,startIdx,cellId);
      break;

    case 1: // --------------------- build line -----------------------

      for (dir[0]=dir[1]=dir[2]=totPoints=0, i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) > 0 )
          {
          dir[0] = i;
          totPoints = diff[i] + 1;
          break;
          }
        }
      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newLines = vtkCellArray::New();
      newLines->Allocate(newLines->EstimateSize(totPoints-1,2));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints - 1);
//
//  Load data
//
      if ( dir[0] == 0 )
        {
        offset[0] = 1;
        }
      else if (dir[0] == 1)
        {
        offset[0] = dims[0];
        }
      else
        {
        offset[0] = dims[0]*dims[1];
        }

      for (i=0; i<totPoints; i++)
        {
        idx = startIdx + i*offset[0];
        input->GetPoint(idx, x);
        ptIds[0] = newPts->InsertNextPoint(x);
        outPD->CopyData(pd,idx,ptIds[0]);
        }

      if ( dir[0] == 0 )
        {
        offset[0] = 1;
        }
      else if (dir[0] == 1)
        {
        offset[0] = dims[0] - 1;
        }
      else
        {
        offset[0] = (dims[0] - 1) * (dims[1] - 1);
        }

      for (i=0; i<(totPoints-1); i++)
        {
        idx = startCellIdx + i*offset[0];
        ptIds[0] = i;
        ptIds[1] = i + 1;
        cellId = newLines->InsertNextCell(2,ptIds);
        outCD->CopyData(cd,idx,cellId);
        }
      break;

    case 2: // --------------------- build plane -----------------------
//
//  Create the data objects
//
      for (dir[0]=dir[1]=dir[2]=idx=0,i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) != 0 )
          {
          dir[idx++] = i;
          }
        else
          {
          dir[2] = i;
          }
        }

      totPoints = (diff[dir[0]]+1) * (diff[dir[1]]+1);
      numPolys = diff[dir[0]]  * diff[dir[1]];

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newPolys = vtkCellArray::New();
      newPolys->Allocate(newLines->EstimateSize(numPolys,4));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,numPolys);
//
//  Create polygons
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          {
          offset[i] = 1;
          }
        else if ( dir[i] == 1 )
          {
          offset[i] = dims[0];
          }
        else if ( dir[i] == 2 )
          {
          offset[i] = dims[0]*dims[1];
          }
        }

      // create points whether visible or not.  Makes coding easier but generates
      // extra data.
      for (pos=startIdx, j=0; j < (diff[dir[1]]+1); j++)
        {
        for (i=0; i < (diff[dir[0]]+1); i++)
          {
          idx = pos + i*offset[0];
          input->GetPoint(idx, x);
          ptIds[0] = newPts->InsertNextPoint(x);
          outPD->CopyData(pd,idx,ptIds[0]);
          }
        pos += offset[1];
        }

      // create any polygon who has a visible vertex.  To turn off a polygon, all
      // vertices have to be blanked.
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          {
          offset[i] = 1;
          }
        else if ( dir[i] == 1 )
          {
          offset[i] = (dims[0] - 1);
          }
        else if ( dir[i] == 2 )
          {
          offset[i] = (dims[0] - 1) * (dims[1] - 1);
          }
        }

      for (pos=startCellIdx, j=0; j < diff[dir[1]]; j++)
        {
        for (i=0; i < diff[dir[0]]; i++)
          {
          idx = pos + i*offset[0];
          ptIds[0] = i + j*(diff[dir[0]]+1);
          ptIds[1] = ptIds[0] + 1;
          ptIds[2] = ptIds[1] + diff[dir[0]] + 1;
          ptIds[3] = ptIds[2] - 1;
          cellId = newPolys->InsertNextCell(4,ptIds);
          outCD->CopyData(cd,idx,cellId);
          }
        pos += offset[1];
        }
      break;

    case 3: // ------------------- grab points in volume  --------------

//
// Create data objects
//
      for (i=0; i<3; i++)
        {
        diff[i] = extent[2*i+1] - extent[2*i];
        }

      totPoints = (diff[0]+1) * (diff[1]+1) * (diff[2]+1);

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(totPoints,1));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints);
//
// Create vertices
//
      offset[0] = dims[0];
      offset[1] = dims[0]*dims[1];

      for (k=0; k < (diff[2]+1); k++)
        {
        for (j=0; j < (diff[1]+1); j++)
          {
          pos = startIdx + j*offset[0] + k*offset[1];
          for (i=0; i < (diff[0]+1); i++)
            {
            input->GetPoint(pos+i, x);
            ptIds[0] = newPts->InsertNextPoint(x);
            outPD->CopyData(pd,pos+i,ptIds[0]);
            cellId = newVerts->InsertNextCell(1,ptIds);
            outCD->CopyData(cd,pos+i,cellId);
            }
          }
        }
        break; /* end this case */

    } // switch
//
// Update self and release memory
//
  if (newPts)
    {
    output->SetPoints(newPts);
    newPts->Delete();
    }

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }

  return 1;
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices.
void vtkRectilinearGridGeometryFilter::SetExtent(int iMin, int iMax, int jMin,
                                                 int jMax, int kMin, int kMax)
{
  int extent[6];

  extent[0] = iMin;
  extent[1] = iMax;
  extent[2] = jMin;
  extent[3] = jMax;
  extent[4] = kMin;
  extent[5] = kMax;

  this->SetExtent(extent);
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices in array form.
void vtkRectilinearGridGeometryFilter::SetExtent(int extent[6])
{
  int i;

  if ( extent[0] != this->Extent[0] || extent[1] != this->Extent[1] ||
  extent[2] != this->Extent[2] || extent[3] != this->Extent[3] ||
  extent[4] != this->Extent[4] || extent[5] != this->Extent[5] )
    {
    this->Modified();
    for (i=0; i<3; i++)
      {
      if ( extent[2*i] < 0 )
        {
        extent[2*i] = 0;
        }
      if ( extent[2*i+1] < extent[2*i] )
        {
        extent[2*i+1] = extent[2*i];
        }
      this->Extent[2*i] = extent[2*i];
      this->Extent[2*i+1] = extent[2*i+1];
      }
    }
}

int vtkRectilinearGridGeometryFilter::FillInputPortInformation(
  int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkRectilinearGrid");
  return 1;
}

void vtkRectilinearGridGeometryFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Extent: \n";
  os << indent << "  Imin,Imax: (" << this->Extent[0] << ", " << this->Extent[1] << ")\n";
  os << indent << "  Jmin,Jmax: (" << this->Extent[2] << ", " << this->Extent[3] << ")\n";
  os << indent << "  Kmin,Kmax: (" << this->Extent[4] << ", " << this->Extent[5] << ")\n";
}
<commit_msg>BUG: Need to handle empty input properly.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRectilinearGridGeometryFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkRectilinearGridGeometryFilter.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkRectilinearGrid.h"

vtkStandardNewMacro(vtkRectilinearGridGeometryFilter);

// Construct with initial extent (0,100, 0,100, 0,0) (i.e., a k-plane).
vtkRectilinearGridGeometryFilter::vtkRectilinearGridGeometryFilter()
{
  this->Extent[0] = 0;
  this->Extent[1] = VTK_LARGE_INTEGER;
  this->Extent[2] = 0;
  this->Extent[3] = VTK_LARGE_INTEGER;
  this->Extent[4] = 0;
  this->Extent[5] = VTK_LARGE_INTEGER;
}

int vtkRectilinearGridGeometryFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkRectilinearGrid *input = vtkRectilinearGrid::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  int *dims, dimension, dir[3], diff[3];
  int i, j, k, extent[6];
  vtkIdType idx, startIdx, startCellIdx;
  vtkIdType ptIds[4];
  vtkIdType cellId;
  vtkPoints *newPts=0;
  vtkCellArray *newVerts=0;
  vtkCellArray *newLines=0;
  vtkCellArray *newPolys=0;
  vtkIdType totPoints, pos;
  int offset[3], numPolys;
  double x[3];
  vtkPointData *pd, *outPD;
  vtkCellData *cd, *outCD;

  vtkDebugMacro(<< "Extracting rectilinear points geometry");

  if (input->GetNumberOfPoints() == 0)
    {
    vtkDebugMacro("Empty input");
    return 1;
    }

  pd = input->GetPointData();
  outPD = output->GetPointData();
  outPD->CopyNormalsOff();
  cd = input->GetCellData();
  outCD = output->GetCellData();
  dims = input->GetDimensions();
  //
  // Based on the dimensions of the rectilinear data,
  // and the extent of the geometry,
  // compute the combined extent plus the dimensionality of the data
  //
  for (dimension=3, i=0; i<3; i++)
    {
    extent[2*i] = this->Extent[2*i] < 0 ? 0 : this->Extent[2*i];
    extent[2*i] = this->Extent[2*i] >= dims[i] ? dims[i]-1 : this->Extent[2*i];
    extent[2*i+1] = this->Extent[2*i+1] >= dims[i] ? dims[i]-1 : this->Extent[2*i+1];
    if ( extent[2*i+1] < extent[2*i] )
      {
      extent[2*i+1] = extent[2*i];
      }
    if ( (extent[2*i+1] - extent[2*i]) == 0 )
      {
      dimension--;
      }
    }
  //
  // Now create polygonal data based on dimension of data
  //
  startIdx = extent[0] + extent[2]*dims[0] + extent[4]*dims[0]*dims[1];
  // The cell index is a bit more complicated at the boundaries
  if (dims[0] == 1)
    {
    startCellIdx = extent[0];
    }
  else
    {
    startCellIdx =  (extent[0] < dims[0] - 1) ? extent[0]
                                              : extent[0]-1;
    }
  if (dims[1] == 1)
    {
    startCellIdx += extent[2]*(dims[0]-1);
    }
  else
    {
    startCellIdx += (extent[2] < dims[1] - 1) ? extent[2]*(dims[0]-1)
                                              : (extent[2]-1)*(dims[0]-1);
    }
  if (dims[2] == 1)
    {
    startCellIdx += extent[4]*(dims[0]-1)*(dims[1]-1);
    }
  else
    {
    startCellIdx += (extent[4] < dims[2] - 1) ? extent[4]*(dims[0]-1)*(dims[1]-1)
                                              : (extent[4]-1)*(dims[0]-1)*(dims[1]-1);
    }

  switch (dimension)
    {
    default:
      break;

    case 0: // --------------------- build point -----------------------

      newPts = vtkPoints::New();
      newPts->Allocate(1);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(1,1));
      outPD->CopyAllocate(pd,1);
      outCD->CopyAllocate(cd,1);

      ptIds[0] = newPts->InsertNextPoint(input->GetPoint(startIdx));
      outPD->CopyData(pd,startIdx,ptIds[0]);

      cellId = newVerts->InsertNextCell(1,ptIds);
      outCD->CopyData(cd,startIdx,cellId);
      break;

    case 1: // --------------------- build line -----------------------

      for (dir[0]=dir[1]=dir[2]=totPoints=0, i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) > 0 )
          {
          dir[0] = i;
          totPoints = diff[i] + 1;
          break;
          }
        }
      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newLines = vtkCellArray::New();
      newLines->Allocate(newLines->EstimateSize(totPoints-1,2));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints - 1);
//
//  Load data
//
      if ( dir[0] == 0 )
        {
        offset[0] = 1;
        }
      else if (dir[0] == 1)
        {
        offset[0] = dims[0];
        }
      else
        {
        offset[0] = dims[0]*dims[1];
        }

      for (i=0; i<totPoints; i++)
        {
        idx = startIdx + i*offset[0];
        input->GetPoint(idx, x);
        ptIds[0] = newPts->InsertNextPoint(x);
        outPD->CopyData(pd,idx,ptIds[0]);
        }

      if ( dir[0] == 0 )
        {
        offset[0] = 1;
        }
      else if (dir[0] == 1)
        {
        offset[0] = dims[0] - 1;
        }
      else
        {
        offset[0] = (dims[0] - 1) * (dims[1] - 1);
        }

      for (i=0; i<(totPoints-1); i++)
        {
        idx = startCellIdx + i*offset[0];
        ptIds[0] = i;
        ptIds[1] = i + 1;
        cellId = newLines->InsertNextCell(2,ptIds);
        outCD->CopyData(cd,idx,cellId);
        }
      break;

    case 2: // --------------------- build plane -----------------------
//
//  Create the data objects
//
      for (dir[0]=dir[1]=dir[2]=idx=0,i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) != 0 )
          {
          dir[idx++] = i;
          }
        else
          {
          dir[2] = i;
          }
        }

      totPoints = (diff[dir[0]]+1) * (diff[dir[1]]+1);
      numPolys = diff[dir[0]]  * diff[dir[1]];

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newPolys = vtkCellArray::New();
      newPolys->Allocate(newLines->EstimateSize(numPolys,4));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,numPolys);
//
//  Create polygons
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          {
          offset[i] = 1;
          }
        else if ( dir[i] == 1 )
          {
          offset[i] = dims[0];
          }
        else if ( dir[i] == 2 )
          {
          offset[i] = dims[0]*dims[1];
          }
        }

      // create points whether visible or not.  Makes coding easier but generates
      // extra data.
      for (pos=startIdx, j=0; j < (diff[dir[1]]+1); j++)
        {
        for (i=0; i < (diff[dir[0]]+1); i++)
          {
          idx = pos + i*offset[0];
          input->GetPoint(idx, x);
          ptIds[0] = newPts->InsertNextPoint(x);
          outPD->CopyData(pd,idx,ptIds[0]);
          }
        pos += offset[1];
        }

      // create any polygon who has a visible vertex.  To turn off a polygon, all
      // vertices have to be blanked.
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          {
          offset[i] = 1;
          }
        else if ( dir[i] == 1 )
          {
          offset[i] = (dims[0] - 1);
          }
        else if ( dir[i] == 2 )
          {
          offset[i] = (dims[0] - 1) * (dims[1] - 1);
          }
        }

      for (pos=startCellIdx, j=0; j < diff[dir[1]]; j++)
        {
        for (i=0; i < diff[dir[0]]; i++)
          {
          idx = pos + i*offset[0];
          ptIds[0] = i + j*(diff[dir[0]]+1);
          ptIds[1] = ptIds[0] + 1;
          ptIds[2] = ptIds[1] + diff[dir[0]] + 1;
          ptIds[3] = ptIds[2] - 1;
          cellId = newPolys->InsertNextCell(4,ptIds);
          outCD->CopyData(cd,idx,cellId);
          }
        pos += offset[1];
        }
      break;

    case 3: // ------------------- grab points in volume  --------------

//
// Create data objects
//
      for (i=0; i<3; i++)
        {
        diff[i] = extent[2*i+1] - extent[2*i];
        }

      totPoints = (diff[0]+1) * (diff[1]+1) * (diff[2]+1);

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(totPoints,1));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints);
//
// Create vertices
//
      offset[0] = dims[0];
      offset[1] = dims[0]*dims[1];

      for (k=0; k < (diff[2]+1); k++)
        {
        for (j=0; j < (diff[1]+1); j++)
          {
          pos = startIdx + j*offset[0] + k*offset[1];
          for (i=0; i < (diff[0]+1); i++)
            {
            input->GetPoint(pos+i, x);
            ptIds[0] = newPts->InsertNextPoint(x);
            outPD->CopyData(pd,pos+i,ptIds[0]);
            cellId = newVerts->InsertNextCell(1,ptIds);
            outCD->CopyData(cd,pos+i,cellId);
            }
          }
        }
        break; /* end this case */

    } // switch
//
// Update self and release memory
//
  if (newPts)
    {
    output->SetPoints(newPts);
    newPts->Delete();
    }

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }

  return 1;
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices.
void vtkRectilinearGridGeometryFilter::SetExtent(int iMin, int iMax, int jMin,
                                                 int jMax, int kMin, int kMax)
{
  int extent[6];

  extent[0] = iMin;
  extent[1] = iMax;
  extent[2] = jMin;
  extent[3] = jMax;
  extent[4] = kMin;
  extent[5] = kMax;

  this->SetExtent(extent);
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices in array form.
void vtkRectilinearGridGeometryFilter::SetExtent(int extent[6])
{
  int i;

  if ( extent[0] != this->Extent[0] || extent[1] != this->Extent[1] ||
  extent[2] != this->Extent[2] || extent[3] != this->Extent[3] ||
  extent[4] != this->Extent[4] || extent[5] != this->Extent[5] )
    {
    this->Modified();
    for (i=0; i<3; i++)
      {
      if ( extent[2*i] < 0 )
        {
        extent[2*i] = 0;
        }
      if ( extent[2*i+1] < extent[2*i] )
        {
        extent[2*i+1] = extent[2*i];
        }
      this->Extent[2*i] = extent[2*i];
      this->Extent[2*i+1] = extent[2*i+1];
      }
    }
}

int vtkRectilinearGridGeometryFilter::FillInputPortInformation(
  int, vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkRectilinearGrid");
  return 1;
}

void vtkRectilinearGridGeometryFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Extent: \n";
  os << indent << "  Imin,Imax: (" << this->Extent[0] << ", " << this->Extent[1] << ")\n";
  os << indent << "  Jmin,Jmax: (" << this->Extent[2] << ", " << this->Extent[3] << ")\n";
  os << indent << "  Kmin,Kmax: (" << this->Extent[4] << ", " << this->Extent[5] << ")\n";
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

#include <thrust/system/cuda/error.h>
#include <thrust/system/cuda/detail/guarded_cuda_runtime_api.h>

namespace thrust
{

namespace system
{

error_code make_error_code(cuda_cub::errc::errc_t e)
{
  return error_code(static_cast<int>(e), cuda_category());
} // end make_error_code()

error_condition make_error_condition(cuda_cub::errc::errc_t e)
{
  return error_condition(static_cast<int>(e), cuda_category());
} // end make_error_condition()

namespace cuda_cub
{

namespace detail
{

class cuda_error_category
  : public error_category
{
  public:
    inline cuda_error_category(void) {}

    inline virtual const char *name(void) const
    {
      return "cuda";
    }

    inline virtual std::string message(int ev) const
    {
      static const std::string unknown_err("Unknown error");
      const char *c_str = ::cudaGetErrorString(static_cast<cudaError_t>(ev));
      return c_str ? std::string(c_str) : unknown_err;
    }

    inline virtual error_condition default_error_condition(int ev) const
    {
      using namespace cuda_cub::errc;

      if(ev < ::cudaErrorApiFailureBase)
      {
        return make_error_condition(static_cast<errc_t>(ev));
      }

      return system_category().default_error_condition(ev);
    }
}; // end cuda_error_category

} // end detail

} // end namespace cuda_cub

const error_category &cuda_category(void)
{
  static const thrust::system::cuda_cub::detail::cuda_error_category result;
  return result;
}

} // end namespace system

} // end namespace thrust

<commit_msg>Change `thrust::system_error` in the CUDA backend to print out its `cudaError_t` enumerator in addition to the diagnostic message.<commit_after>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

#include <thrust/system/cuda/error.h>
#include <thrust/system/cuda/detail/guarded_cuda_runtime_api.h>

namespace thrust
{

namespace system
{

error_code make_error_code(cuda_cub::errc::errc_t e)
{
  return error_code(static_cast<int>(e), cuda_category());
} // end make_error_code()

error_condition make_error_condition(cuda_cub::errc::errc_t e)
{
  return error_condition(static_cast<int>(e), cuda_category());
} // end make_error_condition()

namespace cuda_cub
{

namespace detail
{

class cuda_error_category
  : public error_category
{
  public:
    inline cuda_error_category(void) {}

    inline virtual const char *name(void) const
    {
      return "cuda";
    }

    inline virtual std::string message(int ev) const
    {
      char const* const unknown_str  = "unknown error";
      char const* const unknown_name = "cudaErrorUnknown";
      char const* c_str  = ::cudaGetErrorString(static_cast<cudaError_t>(ev));
      char const* c_name = ::cudaGetErrorName(static_cast<cudaError_t>(ev));
      return std::string(c_name ? c_name : unknown_name)
           + ": " + (c_str ? c_str : unknown_str);
    }

    inline virtual error_condition default_error_condition(int ev) const
    {
      using namespace cuda_cub::errc;

      if(ev < ::cudaErrorApiFailureBase)
      {
        return make_error_condition(static_cast<errc_t>(ev));
      }

      return system_category().default_error_condition(ev);
    }
}; // end cuda_error_category

} // end detail

} // end namespace cuda_cub

const error_category &cuda_category(void)
{
  static const thrust::system::cuda_cub::detail::cuda_error_category result;
  return result;
}

} // end namespace system

} // end namespace thrust

<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "autopilot_tester.h"

TEST_CASE("Fly forward in position control", "[multicopter][vtol]")
{
	AutopilotTester tester;
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	tester.fly_forward_in_posctl();
	std::chrono::seconds until_disarmed_timeout = std::chrono::seconds(60);
	tester.wait_until_disarmed(until_disarmed_timeout);
	tester.check_home_not_within(5.f);
}

TEST_CASE("Fly forward in altitude control", "[multicopter][vtol]")
{
	AutopilotTester tester;
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	tester.fly_forward_in_altctl();
	std::chrono::seconds until_disarmed_timeout = std::chrono::seconds(60);
	tester.wait_until_disarmed(until_disarmed_timeout);
	tester.check_home_not_within(5.f);
}
<commit_msg>mavsdk_tests: increase time for manual tests<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "autopilot_tester.h"

TEST_CASE("Fly forward in position control", "[multicopter][vtol]")
{
	AutopilotTester tester;
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	tester.fly_forward_in_posctl();
	std::chrono::seconds until_disarmed_timeout = std::chrono::seconds(90);
	tester.wait_until_disarmed(until_disarmed_timeout);
	tester.check_home_not_within(5.f);
}

TEST_CASE("Fly forward in altitude control", "[multicopter][vtol]")
{
	AutopilotTester tester;
	tester.connect(connection_url);
	tester.wait_until_ready();
	tester.store_home();
	tester.arm();
	tester.fly_forward_in_altctl();
	std::chrono::seconds until_disarmed_timeout = std::chrono::seconds(90);
	tester.wait_until_disarmed(until_disarmed_timeout);
	tester.check_home_not_within(5.f);
}
<|endoftext|>