<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "test_gradient"

#include <boost/test/unit_test.hpp>
#include "libnanocv/nanocv.h"
#include "libnanocv/accumulator.h"
#include "libnanocv/util/logger.h"
#include "libnanocv/util/close.hpp"
#include "libnanocv/util/random.hpp"
#include "libnanocv/util/epsilon.hpp"
#include "libnanocv/util/thread_pool.h"
#include "libnanocv-test/check_gradients.h"

namespace test
{
        using namespace ncv;

        thread_pool_t::mutex_t mutex;

        size_t n_checks = 0;
        size_t n_failures1 = 0;
        size_t n_failures2 = 0;
        size_t n_failures3 = 0;

        void test_grad_params(const string_t& header, const string_t& loss_id, const model_t& model,
                accumulator_t& acc_params)
        {
                random_t<size_t> rand(8, 16);

                const size_t n_tests = 16;
                const size_t n_samples = rand();

                const rloss_t rloss = loss_manager_t::instance().get(loss_id);
                const loss_t& loss = *rloss;

                const size_t psize = model.psize();
                const size_t isize = model.isize();
                const size_t osize = model.osize();

                vector_t params(psize);
                vectors_t targets(n_samples, vector_t(osize));
                tensors_t inputs(n_samples, tensor_t(model.idims(), model.irows(), model.icols()));

                // optimization problem (wrt parameters & inputs): size
                auto fn_params_size = [&] ()
                {
                        return psize;
                };

                // optimization problem (wrt parameters & inputs): function value
                auto fn_params_fval = [&] (const vector_t& x)
                {
                        acc_params.reset(x);
                        acc_params.update(inputs, targets, loss);

                        return acc_params.value();
                };

                // optimization problem (wrt parameters & inputs): function value & gradient
                auto fn_params_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        acc_params.reset(x);
                        acc_params.update(inputs, targets, loss);

                        gx = acc_params.vgrad();
                        return acc_params.value();
                };

                // construct optimization problem: analytic gradient and finite difference approximation
                const opt_problem_t problem_analytic_params(fn_params_size, fn_params_fval, fn_params_grad);
                const opt_problem_t problem_aproxdif_params(fn_params_size, fn_params_fval);

                for (size_t t = 0; t < n_tests; t ++)
                {
                        random_t<scalar_t> prgen(-0.1, +0.1);
                        random_t<scalar_t> irgen(-0.1, +0.1);
                        random_t<size_t> trgen(0, osize - 1);

                        prgen(params.data(), params.data() + psize);
                        for (vector_t& target : targets)
                        {
                                target = ncv::class_target(trgen(), osize);
                        }
                        for (tensor_t& input : inputs)
                        {
                                irgen(input.data(), input.data() + isize);
                        }

                        vector_t analytic_params_grad, aproxdif_params_grad;

                        problem_analytic_params(params, analytic_params_grad);
                        problem_aproxdif_params(params, aproxdif_params_grad);

                        const scalar_t delta = (analytic_params_grad - aproxdif_params_grad).lpNorm<Eigen::Infinity>();

                        // update statistics
                        const thread_pool_t::lock_t lock(test::mutex);

                        n_checks ++;
                        if (!math::close(delta, scalar_t(0), math::epsilon1<scalar_t>()))
                        {
                                n_failures1 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon2<scalar_t>()))
                        {
                                n_failures2 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon3<scalar_t>()))
                        {
                                n_failures3 ++;

                                BOOST_CHECK_LE(delta, math::epsilon3<scalar_t>());

                                log_error() << header << ": error = " << delta << "/" << math::epsilon3<scalar_t>() << "!";
                        }
                }
        }

        void test_grad_params(const string_t& header, const string_t& loss_id, const model_t& model)
        {
                // check all criteria
                const strings_t criteria = criterion_manager_t::instance().ids();
                for (const string_t& criterion : criteria)
                {
                        random_t<size_t> rand(2, 16);
                        const size_t n_threads = 1 + (rand() % 2);

                        accumulator_t acc_params(model, n_threads, criterion, criterion_t::type::vgrad, 1.0);
                        test_grad_params(header + "[criterion = " + criterion + "]", loss_id, model, acc_params);
                }
        }

        void test_grad_inputs(const string_t& header, const string_t& loss_id, const model_t& model)
        {
                rmodel_t rmodel_inputs = model.clone();

                const size_t n_tests = 256;

                const rloss_t rloss = loss_manager_t::instance().get(loss_id);
                const loss_t& loss = *rloss;

                const size_t psize = model.psize();
                const size_t isize = model.isize();
                const size_t osize = model.osize();

                vector_t params(psize);
                vector_t target(osize);
                tensor_t input(model.idims(), model.irows(), model.icols());

                // optimization problem (wrt parameters & inputs): size
                auto fn_inputs_size = [&] ()
                {
                        return isize;
                };

                // optimization problem (wrt parameters & inputs): function value
                auto fn_inputs_fval = [&] (const vector_t& x)
                {
                        rmodel_inputs->load_params(params);

                        const vector_t output = rmodel_inputs->output(x).vector();

                        return loss.value(target, output);
                };

                // optimization problem (wrt parameters & inputs): function value & gradient
                auto fn_inputs_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        rmodel_inputs->load_params(params);

                        const vector_t output = rmodel_inputs->output(x).vector();

                        gx = rmodel_inputs->ginput(loss.vgrad(target, output)).vector();
                        return loss.value(target, output);
                };

                // construct optimization problem: analytic gradient and finite difference approximation
                const opt_problem_t problem_analytic_inputs(fn_inputs_size, fn_inputs_fval, fn_inputs_grad);
                const opt_problem_t problem_aproxdif_inputs(fn_inputs_size, fn_inputs_fval);

                for (size_t t = 0; t < n_tests; t ++)
                {
                        random_t<scalar_t> prgen(-1.0, +1.0);
                        random_t<scalar_t> irgen(-0.1, +0.1);
                        random_t<size_t> trgen(0, osize - 1);

                        prgen(params.data(), params.data() + psize);
                        target = ncv::class_target(trgen(), osize);
                        irgen(input.data(), input.data() + isize);

                        vector_t analytic_inputs_grad, aproxdif_inputs_grad;

                        problem_analytic_inputs(input.vector(), analytic_inputs_grad);
                        problem_aproxdif_inputs(input.vector(), aproxdif_inputs_grad);

                        const scalar_t delta = (analytic_inputs_grad - aproxdif_inputs_grad).lpNorm<Eigen::Infinity>();

                        // update statistics
                        const thread_pool_t::lock_t lock(test::mutex);

                        n_checks ++;
                        if (!math::close(delta, scalar_t(0), math::epsilon1<scalar_t>()))
                        {
                                n_failures1 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon2<scalar_t>()))
                        {
                                n_failures2 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon3<scalar_t>()))
                        {
                                n_failures3 ++;

                                BOOST_CHECK_LE(delta, math::epsilon3<scalar_t>());

                                log_error() << header << ": error = " << delta << "/" << math::epsilon3<scalar_t>() << "!";
                        }
                }
        }
}

BOOST_AUTO_TEST_CASE(test_gradient)
{
        using namespace ncv;

        ncv::init();

        size_t cmd_irows;
        size_t cmd_icols;
        size_t cmd_outputs;
        color_mode cmd_color;

        auto configs = test::make_grad_configs(cmd_irows, cmd_icols, cmd_outputs, cmd_color);

        // test each configuration
        thread_pool_t pool;
        for (auto config : configs)
        {
                pool.enqueue([=] ()
                {
                        const string_t desc = config.first;
                        const string_t loss_id = config.second;

                        // create model
                        const rmodel_t model = model_manager_t::instance().get("forward-network", desc);
                        BOOST_CHECK_EQUAL(model.operator bool(), true);
                        {
                                const thread_pool_t::lock_t lock(test::mutex);

                                model->resize(cmd_irows, cmd_icols, cmd_outputs, cmd_color, false);
                        }

                        // check with the given loss
                        test::test_grad_params("[loss = " + loss_id + "]", loss_id, *model);
                        test::test_grad_inputs("[loss = " + loss_id + "]", loss_id, *model);
                });
        };

        pool.wait();

        // print statistics
        const scalar_t eps1 = math::epsilon1<scalar_t>();
        const scalar_t eps2 = math::epsilon2<scalar_t>();
        const scalar_t eps3 = math::epsilon3<scalar_t>();

        log_info() << "failures: level1 = " << test::n_failures1 << "/" << test::n_checks << ", epsilon = " << eps1;
        log_info() << "failures: level2 = " << test::n_failures2 << "/" << test::n_checks << ", epsilon = " << eps2;
        log_info() << "failures: level3 = " << test::n_failures3 << "/" << test::n_checks << ", epsilon = " << eps3;

        BOOST_CHECK_LE(test::n_failures1 * 100, 100 * test::n_checks);
        BOOST_CHECK_LE(test::n_failures2 * 100, 5 * test::n_checks);
        BOOST_CHECK_LE(test::n_failures3 * 100, 0 * test::n_checks);
}
<commit_msg>check model size<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "test_gradient"

#include <boost/test/unit_test.hpp>
#include "libnanocv/nanocv.h"
#include "libnanocv/accumulator.h"
#include "libnanocv/util/logger.h"
#include "libnanocv/util/close.hpp"
#include "libnanocv/util/random.hpp"
#include "libnanocv/util/epsilon.hpp"
#include "libnanocv/util/thread_pool.h"
#include "libnanocv-test/check_gradients.h"

namespace test
{
        using namespace ncv;

        thread_pool_t::mutex_t mutex;

        size_t n_checks = 0;
        size_t n_failures1 = 0;
        size_t n_failures2 = 0;
        size_t n_failures3 = 0;

        void test_grad_params(const string_t& header, const string_t& loss_id, const model_t& model,
                accumulator_t& acc_params)
        {
                random_t<size_t> rand(8, 16);

                const size_t n_tests = 16;
                const size_t n_samples = rand();

                const rloss_t rloss = loss_manager_t::instance().get(loss_id);
                const loss_t& loss = *rloss;

                const size_t psize = model.psize();
                const size_t isize = model.isize();
                const size_t osize = model.osize();

                vector_t params(psize);
                vectors_t targets(n_samples, vector_t(osize));
                tensors_t inputs(n_samples, tensor_t(model.idims(), model.irows(), model.icols()));

                // optimization problem (wrt parameters & inputs): size
                auto fn_params_size = [&] ()
                {
                        return psize;
                };

                // optimization problem (wrt parameters & inputs): function value
                auto fn_params_fval = [&] (const vector_t& x)
                {
                        acc_params.reset(x);
                        acc_params.update(inputs, targets, loss);

                        return acc_params.value();
                };

                // optimization problem (wrt parameters & inputs): function value & gradient
                auto fn_params_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        acc_params.reset(x);
                        acc_params.update(inputs, targets, loss);

                        gx = acc_params.vgrad();
                        return acc_params.value();
                };

                // construct optimization problem: analytic gradient and finite difference approximation
                const opt_problem_t problem_analytic_params(fn_params_size, fn_params_fval, fn_params_grad);
                const opt_problem_t problem_aproxdif_params(fn_params_size, fn_params_fval);

                for (size_t t = 0; t < n_tests; t ++)
                {
                        random_t<scalar_t> prgen(-0.1, +0.1);
                        random_t<scalar_t> irgen(-0.1, +0.1);
                        random_t<size_t> trgen(0, osize - 1);

                        prgen(params.data(), params.data() + psize);
                        for (vector_t& target : targets)
                        {
                                target = ncv::class_target(trgen(), osize);
                        }
                        for (tensor_t& input : inputs)
                        {
                                irgen(input.data(), input.data() + isize);
                        }

                        vector_t analytic_params_grad, aproxdif_params_grad;

                        problem_analytic_params(params, analytic_params_grad);
                        problem_aproxdif_params(params, aproxdif_params_grad);

                        const scalar_t delta = (analytic_params_grad - aproxdif_params_grad).lpNorm<Eigen::Infinity>();

                        // update statistics
                        const thread_pool_t::lock_t lock(test::mutex);

                        n_checks ++;
                        if (!math::close(delta, scalar_t(0), math::epsilon1<scalar_t>()))
                        {
                                n_failures1 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon2<scalar_t>()))
                        {
                                n_failures2 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon3<scalar_t>()))
                        {
                                n_failures3 ++;

                                BOOST_CHECK_LE(delta, math::epsilon3<scalar_t>());

                                log_error() << header << ": error = " << delta << "/" << math::epsilon3<scalar_t>() << "!";
                        }
                }
        }

        void test_grad_params(const string_t& header, const string_t& loss_id, const model_t& model)
        {
                // check all criteria
                const strings_t criteria = criterion_manager_t::instance().ids();
                for (const string_t& criterion : criteria)
                {
                        random_t<size_t> rand(2, 16);
                        const size_t n_threads = 1 + (rand() % 2);

                        accumulator_t acc_params(model, n_threads, criterion, criterion_t::type::vgrad, 1.0);
                        test_grad_params(header + "[criterion = " + criterion + "]", loss_id, model, acc_params);
                }
        }

        void test_grad_inputs(const string_t& header, const string_t& loss_id, const model_t& model)
        {
                rmodel_t rmodel_inputs = model.clone();

                const size_t n_tests = 256;

                const rloss_t rloss = loss_manager_t::instance().get(loss_id);
                const loss_t& loss = *rloss;

                const size_t psize = model.psize();
                const size_t isize = model.isize();
                const size_t osize = model.osize();

                vector_t params(psize);
                vector_t target(osize);
                tensor_t input(model.idims(), model.irows(), model.icols());

                // optimization problem (wrt parameters & inputs): size
                auto fn_inputs_size = [&] ()
                {
                        return isize;
                };

                // optimization problem (wrt parameters & inputs): function value
                auto fn_inputs_fval = [&] (const vector_t& x)
                {
                        rmodel_inputs->load_params(params);

                        const vector_t output = rmodel_inputs->output(x).vector();

                        return loss.value(target, output);
                };

                // optimization problem (wrt parameters & inputs): function value & gradient
                auto fn_inputs_grad = [&] (const vector_t& x, vector_t& gx)
                {
                        rmodel_inputs->load_params(params);

                        const vector_t output = rmodel_inputs->output(x).vector();

                        gx = rmodel_inputs->ginput(loss.vgrad(target, output)).vector();
                        return loss.value(target, output);
                };

                // construct optimization problem: analytic gradient and finite difference approximation
                const opt_problem_t problem_analytic_inputs(fn_inputs_size, fn_inputs_fval, fn_inputs_grad);
                const opt_problem_t problem_aproxdif_inputs(fn_inputs_size, fn_inputs_fval);

                for (size_t t = 0; t < n_tests; t ++)
                {
                        random_t<scalar_t> prgen(-1.0, +1.0);
                        random_t<scalar_t> irgen(-0.1, +0.1);
                        random_t<size_t> trgen(0, osize - 1);

                        prgen(params.data(), params.data() + psize);
                        target = ncv::class_target(trgen(), osize);
                        irgen(input.data(), input.data() + isize);

                        vector_t analytic_inputs_grad, aproxdif_inputs_grad;

                        problem_analytic_inputs(input.vector(), analytic_inputs_grad);
                        problem_aproxdif_inputs(input.vector(), aproxdif_inputs_grad);

                        const scalar_t delta = (analytic_inputs_grad - aproxdif_inputs_grad).lpNorm<Eigen::Infinity>();

                        // update statistics
                        const thread_pool_t::lock_t lock(test::mutex);

                        n_checks ++;
                        if (!math::close(delta, scalar_t(0), math::epsilon1<scalar_t>()))
                        {
                                n_failures1 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon2<scalar_t>()))
                        {
                                n_failures2 ++;
                        }
                        if (!math::close(delta, scalar_t(0), math::epsilon3<scalar_t>()))
                        {
                                n_failures3 ++;

                                BOOST_CHECK_LE(delta, math::epsilon3<scalar_t>());

                                log_error() << header << ": error = " << delta << "/" << math::epsilon3<scalar_t>() << "!";
                        }
                }
        }
}

BOOST_AUTO_TEST_CASE(test_gradient)
{
        using namespace ncv;

        ncv::init();

        size_t cmd_irows;
        size_t cmd_icols;
        size_t cmd_outputs;
        color_mode cmd_color;

        auto configs = test::make_grad_configs(cmd_irows, cmd_icols, cmd_outputs, cmd_color);

        // test each configuration
        thread_pool_t pool;
        for (auto config : configs)
        {
                pool.enqueue([=] ()
                {
                        const string_t desc = config.first;
                        const string_t loss_id = config.second;

                        // create model
                        const rmodel_t model = model_manager_t::instance().get("forward-network", desc);
                        BOOST_CHECK_EQUAL(model.operator bool(), true);
                        {
                                const thread_pool_t::lock_t lock(test::mutex);

                                model->resize(cmd_irows, cmd_icols, cmd_outputs, cmd_color, false);
                                BOOST_CHECK_EQUAL(model->irows(), cmd_irows);
                                BOOST_CHECK_EQUAL(model->icols(), cmd_icols);
                                BOOST_CHECK_EQUAL(model->osize(), cmd_outputs);
                                BOOST_CHECK_EQUAL(model->color(), cmd_color);
                        }

                        // check with the given loss
                        test::test_grad_params("[loss = " + loss_id + "]", loss_id, *model);
                        test::test_grad_inputs("[loss = " + loss_id + "]", loss_id, *model);
                });
        };

        pool.wait();

        // print statistics
        const scalar_t eps1 = math::epsilon1<scalar_t>();
        const scalar_t eps2 = math::epsilon2<scalar_t>();
        const scalar_t eps3 = math::epsilon3<scalar_t>();

        log_info() << "failures: level1 = " << test::n_failures1 << "/" << test::n_checks << ", epsilon = " << eps1;
        log_info() << "failures: level2 = " << test::n_failures2 << "/" << test::n_checks << ", epsilon = " << eps2;
        log_info() << "failures: level3 = " << test::n_failures3 << "/" << test::n_checks << ", epsilon = " << eps3;

        BOOST_CHECK_LE(test::n_failures1 * 100, 100 * test::n_checks);
        BOOST_CHECK_LE(test::n_failures2 * 100, 5 * test::n_checks);
        BOOST_CHECK_LE(test::n_failures3 * 100, 0 * test::n_checks);
}
<|endoftext|>


<commit_before>#include "single_producer_sequencer.h"
#include "multi_producer_sequencer.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <functional>
#include <thread>
#include <condition_variable>
#include "blocking_wait_strategy.h"
#include "sequence.h"
#include "sequence_barrier.h"

using namespace magic_bean;

enum ProducerType {
  SINGLE,
  MULTI
};

class MockWaitStrategy : public WaitStrategy {
 public:
  virtual int64_t WaitFor(int64_t sequence, SequencePtr cursor, SequencePtr dependent_sequence,
                          SequenceBarrier* barrier) throw (AlertException, TimeoutException) override {
    return 0;
  }

  MOCK_METHOD0(SignalAllWhenBlocking, void());
};

class SequencerTest : public ::testing::TestWithParam<int> {
 public:
  void Execute() {
    {
      std::unique_lock<std::mutex> waiting_lock(waiting_mutex);
      waiting_cond.notify_all();
    }
    int64_t next = sequencer->Next();
    sequencer->Publish(next);
    {
      std::unique_lock<std::mutex> done_lock(done_mutex);
      done_cond.notify_all();
    }
  }
 protected:
  SequencerTest() {
    producer_type = GetParam();
  }
  virtual ~SequencerTest() {};

  virtual void SetUp() {
    wait_strategy = new BlockingWaitStrategy();
    sequencer = NewProducer(producer_type, wait_strategy);
    gating_sequence = SequencePtr(new Sequence());
    gating_sequences.push_back(gating_sequence);
  }
  virtual void TearDown() {
    gating_sequences.clear();
    gating_sequence.reset();
    delete sequencer;
    delete wait_strategy;
  }

  Sequencer* NewProducer(int producer_type, WaitStrategy* strategy) {
    if(producer_type == ProducerType::SINGLE)
      return new SingleProducerSequencer(BUFFER_SIZE, strategy);
    else if(producer_type == ProducerType::MULTI)
      return new MultiProducerSequencer(BUFFER_SIZE, strategy);
    return nullptr;
  }
 protected:
  int producer_type;
  Sequencer* sequencer;
  WaitStrategy* wait_strategy;
  SequencePtr gating_sequence;
  std::vector<SequencePtr> gating_sequences;

  std::condition_variable waiting_cond;
  std::mutex waiting_mutex;
  std::condition_variable done_cond;
  std::mutex done_mutex;

  static const int BUFFER_SIZE = 16;
  static const int64_t INITIAL_CURSOR_VALUE = -1;
};

TEST_P(SequencerTest, should_start_with_initial_value) {
  ASSERT_EQ(0, sequencer->Next());
}

TEST_P(SequencerTest, should_batch_claim) {
  ASSERT_EQ(3, sequencer->Next(4));
}

TEST_P(SequencerTest, should_indicate_has_available_capacity) {
  sequencer->AddGatingSequences(gating_sequences);

  ASSERT_TRUE(sequencer->HasAvailableCapacity(1));
  ASSERT_TRUE(sequencer->HasAvailableCapacity(BUFFER_SIZE));
  ASSERT_FALSE(sequencer->HasAvailableCapacity(BUFFER_SIZE + 1));

  sequencer->Publish(sequencer->Next());
  ASSERT_TRUE(sequencer->HasAvailableCapacity(BUFFER_SIZE - 1));
  ASSERT_FALSE(sequencer->HasAvailableCapacity(BUFFER_SIZE));
}

TEST_P(SequencerTest, should_indicate_no_available_capacity) {
  sequencer->AddGatingSequences(gating_sequences);

  int64_t sequence = sequencer->Next(16);
  sequencer->Publish(sequence - (BUFFER_SIZE - 1), sequence);
  ASSERT_FALSE(sequencer->HasAvailableCapacity(1));
}

TEST_P(SequencerTest, should_holdup_publisher_when_buffer_is_full) {
  sequencer->AddGatingSequences(gating_sequences);

  int64_t sequence = sequencer->Next(BUFFER_SIZE);
  sequencer->Publish(sequence - (BUFFER_SIZE - 1), sequence);

  std::unique_lock<std::mutex> waiting_lock(waiting_mutex);
  std::unique_lock<std::mutex> done_lock(done_mutex);

  int64_t expected_full_sequence = INITIAL_CURSOR_VALUE + sequencer->GetBufferSize();
  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence);

  std::thread thread(std::bind(&SequencerTest::Execute, this));

  waiting_cond.wait(waiting_lock);
  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence);
  gating_sequence->Set(INITIAL_CURSOR_VALUE + 1);
  done_cond.wait(done_lock);

  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence + 1);
  thread.join();
}

TEST_P(SequencerTest, should_throw_insufficient_capacity_exception_when_sequencer_is_full) {
  sequencer->AddGatingSequences(gating_sequences);

  for(int i = 0; i < BUFFER_SIZE; i++) {
    sequencer->Next();
  }

  try {
    sequencer->TryNext();
  } catch(InsufficientCapacityException& ex) {
    SUCCEED();
  } catch(...) {
    FAIL() << "Unexpected exception";
  }
}

TEST_P(SequencerTest, should_calculate_remaining_capacity) {
  sequencer->AddGatingSequences(gating_sequences);
  ASSERT_EQ(sequencer->RemainingCapacity(), int64_t(BUFFER_SIZE));

  for(int i = 1; i < BUFFER_SIZE; i++) {
    sequencer->Next();
    ASSERT_EQ(sequencer->RemainingCapacity(), BUFFER_SIZE - i);
  }
}

TEST_P(SequencerTest, should_not_be_available_until_published) {
  int64_t next = sequencer->Next(6);
  for(int i = 0; i <= 5; i++)
    ASSERT_FALSE(sequencer->IsAvailable(i));

  sequencer->Publish(next - (6 - 1), next);
  for(int i = 0; i <= 5; i++)
    ASSERT_TRUE(sequencer->IsAvailable(i));
  ASSERT_FALSE(sequencer->IsAvailable(6));
}

TEST_P(SequencerTest, should_notify_wait_strategy_on_publish) {
  MockWaitStrategy* wait_strategy = new MockWaitStrategy;
  Sequenced* sequencer = NewProducer(producer_type, wait_strategy);

  EXPECT_CALL(*wait_strategy, SignalAllWhenBlocking());
  sequencer->Publish(sequencer->Next());
  delete sequencer;
  delete wait_strategy;
}

TEST_P(SequencerTest, should_notify_wait_strategy_on_publish_batch) {
  MockWaitStrategy* wait_strategy = new MockWaitStrategy;
  Sequenced* sequencer = NewProducer(producer_type, wait_strategy);

  EXPECT_CALL(*wait_strategy, SignalAllWhenBlocking());
  int64_t next = sequencer->Next(4);
  sequencer->Publish(next - (4 - 1), next);
  delete sequencer;
  delete wait_strategy;
}

TEST_P(SequencerTest, should_wait_on_publication) {
  std::vector<SequencePtr> sequences_to_track;
  SequenceBarrier* barrier = sequencer->NewBarrier(sequences_to_track);
  int64_t next = sequencer->Next(10);
  int64_t lo = next - (10 - 1);
  int64_t mid = next - 5;

  for(int64_t l = lo; l < mid; l++)
    sequencer->Publish(l);

  ASSERT_EQ(barrier->WaitFor(-1), mid - 1);

  for(int64_t l = mid; l <= next; l++)
    sequencer->Publish(l);

  ASSERT_EQ(barrier->WaitFor(-1), next);
  delete barrier;
}

TEST_P(SequencerTest, should_try_next) {
  sequencer->AddGatingSequences(gating_sequences);
  for(int i = 0; i < BUFFER_SIZE; i++)
    sequencer->Publish(sequencer->TryNext());

  try {
    sequencer->TryNext();
  } catch(InsufficientCapacityException& ex) {
    SUCCEED();
  }
}

INSTANTIATE_TEST_CASE_P(AllProducerSequencerTest, SequencerTest, ::testing::Range(0, 2));
<commit_msg>add test sequencer case.<commit_after>#include "single_producer_sequencer.h"
#include "multi_producer_sequencer.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <functional>
#include <thread>
#include <condition_variable>
#include "blocking_wait_strategy.h"
#include "sequence.h"
#include "sequence_barrier.h"

using namespace magic_bean;

enum ProducerType {
  SINGLE,
  MULTI
};

class MockWaitStrategy : public WaitStrategy {
 public:
  virtual int64_t WaitFor(int64_t sequence, SequencePtr cursor, SequencePtr dependent_sequence,
                          SequenceBarrier* barrier) throw (AlertException, TimeoutException) override {
    return 0;
  }

  MOCK_METHOD0(SignalAllWhenBlocking, void());
};

class SequencerTest : public ::testing::TestWithParam<int> {
 public:
  void Execute() {
    {
      std::unique_lock<std::mutex> waiting_lock(waiting_mutex);
      waiting_cond.notify_all();
    }
    int64_t next = sequencer->Next();
    sequencer->Publish(next);
    {
      std::unique_lock<std::mutex> done_lock(done_mutex);
      done_cond.notify_all();
    }
  }
 protected:
  SequencerTest() {
    producer_type = GetParam();
  }
  virtual ~SequencerTest() {};

  virtual void SetUp() {
    wait_strategy = new BlockingWaitStrategy();
    sequencer = NewProducer(producer_type, wait_strategy);
    gating_sequence = SequencePtr(new Sequence());
    gating_sequences.push_back(gating_sequence);
  }
  virtual void TearDown() {
    gating_sequences.clear();
    gating_sequence.reset();
    delete sequencer;
    delete wait_strategy;
  }

  Sequencer* NewProducer(int producer_type, WaitStrategy* strategy) {
    if(producer_type == ProducerType::SINGLE)
      return new SingleProducerSequencer(BUFFER_SIZE, strategy);
    else if(producer_type == ProducerType::MULTI)
      return new MultiProducerSequencer(BUFFER_SIZE, strategy);
    return nullptr;
  }
 protected:
  int producer_type;
  Sequencer* sequencer;
  WaitStrategy* wait_strategy;
  SequencePtr gating_sequence;
  std::vector<SequencePtr> gating_sequences;

  std::condition_variable waiting_cond;
  std::mutex waiting_mutex;
  std::condition_variable done_cond;
  std::mutex done_mutex;

  static const int BUFFER_SIZE = 16;
  static const int64_t INITIAL_CURSOR_VALUE = -1;
};

TEST_P(SequencerTest, should_start_with_initial_value) {
  ASSERT_EQ(0, sequencer->Next());
}

TEST_P(SequencerTest, should_batch_claim) {
  ASSERT_EQ(3, sequencer->Next(4));
}

TEST_P(SequencerTest, should_indicate_has_available_capacity) {
  sequencer->AddGatingSequences(gating_sequences);

  ASSERT_TRUE(sequencer->HasAvailableCapacity(1));
  ASSERT_TRUE(sequencer->HasAvailableCapacity(BUFFER_SIZE));
  ASSERT_FALSE(sequencer->HasAvailableCapacity(BUFFER_SIZE + 1));

  sequencer->Publish(sequencer->Next());
  ASSERT_TRUE(sequencer->HasAvailableCapacity(BUFFER_SIZE - 1));
  ASSERT_FALSE(sequencer->HasAvailableCapacity(BUFFER_SIZE));
}

TEST_P(SequencerTest, should_indicate_no_available_capacity) {
  sequencer->AddGatingSequences(gating_sequences);

  int64_t sequence = sequencer->Next(16);
  sequencer->Publish(sequence - (BUFFER_SIZE - 1), sequence);
  ASSERT_FALSE(sequencer->HasAvailableCapacity(1));
}

TEST_P(SequencerTest, should_holdup_publisher_when_buffer_is_full) {
  sequencer->AddGatingSequences(gating_sequences);

  int64_t sequence = sequencer->Next(BUFFER_SIZE);
  sequencer->Publish(sequence - (BUFFER_SIZE - 1), sequence);

  std::unique_lock<std::mutex> waiting_lock(waiting_mutex);
  std::unique_lock<std::mutex> done_lock(done_mutex);

  int64_t expected_full_sequence = INITIAL_CURSOR_VALUE + sequencer->GetBufferSize();
  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence);

  std::thread thread(std::bind(&SequencerTest::Execute, this));

  waiting_cond.wait(waiting_lock);
  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence);
  gating_sequence->Set(INITIAL_CURSOR_VALUE + 1);
  done_cond.wait(done_lock);

  ASSERT_EQ(sequencer->GetCursor(), expected_full_sequence + 1);
  thread.join();
}

TEST_P(SequencerTest, should_throw_insufficient_capacity_exception_when_sequencer_is_full) {
  sequencer->AddGatingSequences(gating_sequences);

  for(int i = 0; i < BUFFER_SIZE; i++) {
    sequencer->Next();
  }

  try {
    sequencer->TryNext();
  } catch(InsufficientCapacityException& ex) {
    SUCCEED();
  } catch(...) {
    FAIL() << "Unexpected exception";
  }
}

TEST_P(SequencerTest, should_calculate_remaining_capacity) {
  sequencer->AddGatingSequences(gating_sequences);
  ASSERT_EQ(sequencer->RemainingCapacity(), int64_t(BUFFER_SIZE));

  for(int i = 1; i < BUFFER_SIZE; i++) {
    sequencer->Next();
    ASSERT_EQ(sequencer->RemainingCapacity(), BUFFER_SIZE - i);
  }
}

TEST_P(SequencerTest, should_not_be_available_until_published) {
  int64_t next = sequencer->Next(6);
  for(int i = 0; i <= 5; i++)
    ASSERT_FALSE(sequencer->IsAvailable(i));

  sequencer->Publish(next - (6 - 1), next);
  for(int i = 0; i <= 5; i++)
    ASSERT_TRUE(sequencer->IsAvailable(i));
  ASSERT_FALSE(sequencer->IsAvailable(6));
}

TEST_P(SequencerTest, should_notify_wait_strategy_on_publish) {
  MockWaitStrategy* wait_strategy = new MockWaitStrategy;
  Sequenced* sequencer = NewProducer(producer_type, wait_strategy);

  EXPECT_CALL(*wait_strategy, SignalAllWhenBlocking());
  sequencer->Publish(sequencer->Next());
  delete sequencer;
  delete wait_strategy;
}

TEST_P(SequencerTest, should_notify_wait_strategy_on_publish_batch) {
  MockWaitStrategy* wait_strategy = new MockWaitStrategy;
  Sequenced* sequencer = NewProducer(producer_type, wait_strategy);

  EXPECT_CALL(*wait_strategy, SignalAllWhenBlocking());
  int64_t next = sequencer->Next(4);
  sequencer->Publish(next - (4 - 1), next);
  delete sequencer;
  delete wait_strategy;
}

TEST_P(SequencerTest, should_wait_on_publication) {
  std::vector<SequencePtr> sequences_to_track;
  SequenceBarrier* barrier = sequencer->NewBarrier(sequences_to_track);
  int64_t next = sequencer->Next(10);
  int64_t lo = next - (10 - 1);
  int64_t mid = next - 5;

  for(int64_t l = lo; l < mid; l++)
    sequencer->Publish(l);

  ASSERT_EQ(barrier->WaitFor(-1), mid - 1);

  for(int64_t l = mid; l <= next; l++)
    sequencer->Publish(l);

  ASSERT_EQ(barrier->WaitFor(-1), next);
  delete barrier;
}

TEST_P(SequencerTest, should_try_next) {
  sequencer->AddGatingSequences(gating_sequences);
  for(int i = 0; i < BUFFER_SIZE; i++)
    sequencer->Publish(sequencer->TryNext());

  try {
    sequencer->TryNext();
  } catch(InsufficientCapacityException& ex) {
    SUCCEED();
  }
}

TEST_P(SequencerTest, should_claim_specific_sequence) {
  int64_t sequence = 14;
  sequencer->Claim(sequence);
  sequencer->Publish(sequence);
  ASSERT_EQ(sequencer->Next(), sequence + 1);
}

INSTANTIATE_TEST_CASE_P(AllProducerSequencerTest, SequencerTest, ::testing::Range(0, 2));
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// stl
#include <iomanip>
#include <fstream>
#include <numeric>

#include "report.hpp"

namespace visual_tests
{

void console_report::report(result const & r)
{
    s << '"' << r.name << '-' << r.size.width << '-' << r.size.height << '-' << std::fixed <<
        std::setprecision(1) << r.scale_factor << "\" with " << r.renderer_name << "... ";

    switch (r.state)
    {
        case STATE_OK:
            s << "OK";
            break;
        case STATE_FAIL:
            s << "FAILED (" << r.diff << " different pixels)";
            break;
        case STATE_OVERWRITE:
            s << "OVERWRITTEN (" << r.diff << " different pixels)";
            break;
        case STATE_ERROR:
            s << "ERROR (" << r.error_message << ")";
            break;
    }

    s << std::endl;
}

unsigned console_report::summary(result_list const & results)
{
    unsigned ok = 0;
    unsigned error = 0;
    unsigned fail = 0;
    unsigned overwrite = 0;

    for (auto const & r : results)
    {
        switch (r.state)
        {
            case STATE_OK: ok++; break;
            case STATE_FAIL: fail++; break;
            case STATE_ERROR: error++; break;
            case STATE_OVERWRITE: overwrite++; break;
        }
    }

    s << std::endl;
    s << "Visual rendering: " << fail << " failed / " << ok << " passed / "
        << overwrite << " overwritten / " << error << " errors" << std::endl;

    return fail + error;
}

void console_short_report::report(result const & r)
{
    s << '.';
}

void html_report::report(result const & r, boost::filesystem::path const & output_dir)
{
    using namespace boost::filesystem;

    path reference = output_dir / r.reference_image_path.filename();
    path actual = output_dir / r.actual_image_path.filename();

    copy_file(r.reference_image_path, reference, copy_option::overwrite_if_exists);
    copy_file(r.actual_image_path, actual, copy_option::overwrite_if_exists);

     s << "
\n"
          "  <a href=" << reference.filename() << ">\n"
          "    <img src=" << reference.filename() << " width=\"100\%\">\n"
          "  \n"
          "
\n"
          "
" << r.diff << "
\n"
          "
\n"
          "  <a href=" << actual.filename() << ">\n"
          "    <img src=" << actual.filename() << " width=\"100\%\">\n"
          "  \n"
          "
\n";
}

constexpr const char * html_header = R"template(<!DOCTYPE html>

expected

% difference

actual

)template";

constexpr const char * html_footer = R"template(

)template";

void html_report::summary(result_list const & results, boost::filesystem::path const & output_dir)
{
    s << html_header;

    for (auto const & r : results)
    {
        if (r.state != STATE_OK)
        {
            report(r, output_dir);
        }
    }

    s << html_footer;
}

void html_summary(result_list const & results, boost::filesystem::path output_dir)
{
    boost::filesystem::path html_root = output_dir / "visual-test-results";
    ensure_dir(html_root);
    boost::filesystem::path html_report_path = html_root / "comparison.html";
    std::ofstream output_file(html_report_path.string());
    html_report report(output_file);
    report.summary(results, html_root);
}

}
<commit_msg>visual tests: show errors when hit both in console and in html report<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// stl
#include <iomanip>
#include <fstream>
#include <numeric>

#include "report.hpp"

namespace visual_tests
{

void console_report::report(result const & r)
{
    s << '"' << r.name << '-' << r.size.width << '-' << r.size.height << '-' << std::fixed <<
        std::setprecision(1) << r.scale_factor << "\" with " << r.renderer_name << "... ";

    switch (r.state)
    {
        case STATE_OK:
            s << "OK";
            break;
        case STATE_FAIL:
            s << "FAILED (" << r.diff << " different pixels)";
            break;
        case STATE_OVERWRITE:
            s << "OVERWRITTEN (" << r.diff << " different pixels)";
            break;
        case STATE_ERROR:
            s << "ERROR (" << r.error_message << ")";
            break;
    }

    s << std::endl;
}

unsigned console_report::summary(result_list const & results)
{
    unsigned ok = 0;
    unsigned error = 0;
    unsigned fail = 0;
    unsigned overwrite = 0;

    for (auto const & r : results)
    {
        switch (r.state)
        {
            case STATE_OK: ok++; break;
            case STATE_FAIL: fail++; break;
            case STATE_ERROR: error++; break;
            case STATE_OVERWRITE: overwrite++; break;
        }
    }

    s << std::endl;
    s << "Visual rendering: " << fail << " failed / " << ok << " passed / "
        << overwrite << " overwritten / " << error << " errors" << std::endl;

    return fail + error;
}

void console_short_report::report(result const & r)
{
    switch (r.state)
    {
        case STATE_OK:
            s << ".";
            break;
        case STATE_FAIL:
            s << "✘";
            break;
        case STATE_OVERWRITE:
            s << "✓";
            break;
        case STATE_ERROR:
            s << "ERROR (" << r.error_message << ")\n";
            break;
    }
}

void html_report::report(result const & r, boost::filesystem::path const & output_dir)
{
    if (r.state == STATE_ERROR)
    {
       s << "
Failed to render: " << r.name << "
" << r.error_message << "
\n";
    }
    else if (r.state == STATE_FAIL)
    {
      using namespace boost::filesystem;

      path reference = output_dir / r.reference_image_path.filename();
      path actual = output_dir / r.actual_image_path.filename();

      copy_file(r.reference_image_path, reference, copy_option::overwrite_if_exists);
      copy_file(r.actual_image_path, actual, copy_option::overwrite_if_exists);

       s << "
\n"
            "  <a href=" << reference.filename() << ">\n"
            "    <img src=" << reference.filename() << " width=\"100\%\">\n"
            "  \n"
            "
\n"
            "
" << r.diff << "
\n"
            "
\n"
            "  <a href=" << actual.filename() << ">\n"
            "    <img src=" << actual.filename() << " width=\"100\%\">\n"
            "  \n"
            "
\n";
    }
}

constexpr const char * html_header = R"template(<!DOCTYPE html>

expected

% difference

actual

)template";

constexpr const char * html_footer = R"template(

)template";

void html_report::summary(result_list const & results, boost::filesystem::path const & output_dir)
{
    s << html_header;

    for (auto const & r : results)
    {
        if (r.state != STATE_OK)
        {
            report(r, output_dir);
        }
    }

    s << html_footer;
}

void html_summary(result_list const & results, boost::filesystem::path output_dir)
{
    boost::filesystem::path html_root = output_dir / "visual-test-results";
    ensure_dir(html_root);
    boost::filesystem::path html_report_path = html_root / "index.html";
    std::clog << "View failure report at " << html_report_path << "\n";
    std::ofstream output_file(html_report_path.string());
    html_report report(output_file);
    report.summary(results, html_root);
}

}
<|endoftext|>


<commit_before>//
// Trie
//
struct Trie {
	struct Node {
		int ch[8];
		int n;
	};
	Node nodes[MAX_NODES];
	int sz;
	void init() { Zero(nodes); sz = 1; }
	int insert(const char *s) {
		int idx, cur = 0;
		for (; *s; ++s) {
			idx = toupper(s[i]) - 'A';
			if (! nodes[cur].ch[idx])
				nodes[cur].ch[idx] = sz++;
			cur = nodes[cur].ch[idx];
		}
		return ++nodes[cur].n;
	}
};

//
// Hash Map
//
struct HashT {
	int k, v;

	HashT() {}
	HashT(int K, int V): k(K), v(V) {}

	bool operator==(const HashT &x) const { return k == x.k; }
};
#define HASHB (1<<15)
#define HASHN 1000000
#define HASHT_SZ (sizeof(int))
#define HASHT_PTR(x) (reinterpret_cast<u8*>(&( (x).k )))
struct HashMap {
	HashT data[HASHN];
	int next[HASHN];
	int buckets[HASHB];
	int n;

	void init() { Neg(buckets); n = 0; }
	u32 fnv_hash(const u8 *p, int n) const {
		u32 h = 2166136261U;
		for (int i = 0; i < n; ++i) h = (h * 16777619U) ^ p[i];
		return h;
	}
	HashT *add(HashT &h, bool &found) {
		int b = fnv_hash(HASHT_PTR(h), HASHT_SZ) % HASHB;
		for (int i = buckets[b]; i >= 0; i = next[i])
			if (data[i] == h) { found = true; return &data[i]; }
		found = false, next[n] = buckets[b], buckets[b] = n, data[n] = h;
		return &data[n++];
	}
};

//
// Binary Indexed Tree
//
struct Bit {
	BitT f[MAXBIT + 1];
	int n;
	void init(int N) { n=N; Clr(f); }
	void add(int i, BitT v) { while (i <= n) { f[i] += v; i += GetFS(i); } }
	BitT query(int i) { BitT r = 0; for (;i; ClrFS(i)) r += f[i]; return r; }
	BitT query(int from, int to) { return query(to) - query(from - 1); }
};

//
// Segment Tree
//
#define TreeIsLeaf (a == b)
#define TreeIsOut  (j < a || b < i)
#define TreeIsIn   (i <= a && b <= j)
#define TreeLeft   2*x, a, (a+b)/2
#define TreeRight  2*x+1, (a+b)/2+1, b

#define Tree  (T[x])
#define Left  (T[2*x])
#define Right (T[2*x+1])

#define LOGN 19  // 1 + ceil(log2(MAXN))
struct SegTreeH {
	struct Node {
		int i;  // some value
		int p;  // propagation
	};

	Node T[1 << LOGN];
	int n;

	void init(int N) { n = N; init(1, 0, n-1); }
	void init(int x, int a, int b) {
		Tree.i = Tree.p = -1;
		if (TreeIsLeaf) return;
		init(TreeLeft);
		init(TreeRight);
	}

	void propagate(int x, int a, int b) {
		if (Tree.p < 0) return;
		Tree.i = Tree.p;
		if (! TreeIsLeaf)
			Left.p = Right.p = Tree.p;
		Tree.p = -1;
	}

	void update(int i, int j, int v) { update(i, j, v, 1, 0, n-1); }
	void update(int i, int j, int v, int x, int a, int b) {
		propagate(x, a, b);
		if (TreeIsOut) return;
		if (TreeIsLeaf) { Tree.i = v; return; }

		if (TreeIsIn) {
			Tree.i = v;
			Left.p = Right.p = v;
			return;
		}
		update(i, j, v, TreeLeft);
		update(i, j, v, TreeRight);
		Tree.i = Right.i;
	}

	int query(int i, int j) { return query(i, j, 1, 0, n-1); }
	int query(int i, int j, int x, int a, int b) {
		if (TreeIsOut) return -1;
		propagate(x, a, b);
		if (TreeIsIn) return Tree.i;
		int q1 = query(i, j, TreeLeft);
		int q2 = query(i, j, TreeRight);
		return max(q1, q2);
	}

};

//
// R-Tree for 2D matrices
//
const int MAX_ROWS = MAXN;
const int MAX_COLS = MAXN;
const int MAX_H    = 19;   // 1 + ceil(log2(MAX_ROWS * MAX_COLS))
template <typename NT>
struct R2Tree {
	struct Node { NT v; };

	Node T[1 << MAX_H];
	NT	 M[MAX_ROWS][MAX_COLS];
	int  r, c;

	void init(int R, int C) { tree_init(1, 0, 0, r=R, c=C, 0); }
	void tree_init(int x, int r1, int c1, int r2, int c2, int o) {
		if (r1 == r2 && c1 == c2) {
			T[x].v = M[r1][c1];
			return;
		}

		int op = (o + 1) % 2;
		int lt = 2*x, rt = lt + 1;
		if ((o == 0 && c1 < c2) || r1 == r2) {
			int md = (c1 + c2) / 2;
			tree_init(lt, r1, c1, r2, md, op);
			tree_init(rt, r1, md + 1, r2, c2, op);
		}
		else {
			int md = (r1 + r2) / 2;
			tree_init(lt, r1, c1, md, c2, op);
			tree_init(rt, md + 1, c1, r2, c2, op);
		}
		T[x].v = max(T[lt].v, T[rt].v);
	}

	int qr1, qc1, qr2, qc2;
	NT get(int r1, int c1, int r2, int c2) {
		qr1 = r1, qc1 = c1, qr2 = r2, qc2 = c2;
		return tree_get(1, 0, 0, r, c, 0);
	}
	NT tree_get(int x, int r1, int c1, int r2, int c2, int o) {
		if (r1 >= qr1 && r2 <= qr2 && c1 >= qc1 && c2 <= qc2) return T[x].v;
		if (r1 > qr2 || r2 < qr1 || c1 > qc2 || c2 < qc1) return -1;

		int op = (o + 1) % 2;
		int lt = 2*x, rt = lt + 1;
		NT a, b;
		if ((o == 0 && c1 < c2) || r1 == r2) {
			int md = (c1 + c2) / 2;
			a = tree_get(lt, r1, c1, r2, md, op);
			b = tree_get(rt, r1, md + 1, r2, c2, op);
		}
		else {
			int md = (r1 + r2) / 2;
			a = tree_get(lt, r1, c1, md, c2, op);
			b = tree_get(rt, md + 1, c1, r2, c2, op);
		}
		return max(a, b);
	}
};

//
// Lowest Common Ancestor
//
struct LCA {
	int L[MAXN];        // L[i]: level of node i
	int A[MAXN][LOGN];  // A[i][j]: 2^j'th ancestor of i
	int n, h, lh;       // n, height, log(h)
	LCA() {}

	void init(int N, int H) { n=N, h=H; Neg(A); lh = log2(h); }
	void process() {
		// precond: A[i][0] is set for all i
		for (int j = 1, p = 2; p < h; ++j, p <<= 1)
			for (int i = 0; i < n; ++i)
				if (A[i][j-1] != -1)
					A[i][j] = A[ A[i][j-1] ][j-1];
	}
	int query_orig(int a, int b) {
		if (L[a] < L[b]) swap(a, b);

		for (int i = lh, p = 1 << lh; i >= 0; --i, p >>= 1)
			if (L[a] - p >= L[b]) a = A[a][i];
		if (a == b) return a;

		for (int i = lh; i >= 0; --i)
			if (A[a][i] != -1 && A[a][i] != A[b][i])
				a = A[a][i], b = A[b][i];
		return A[a][0];
	}
};

//
// Sparse Table
//
struct SparseTable {
	SparseT A[MAX_SPARSE];
	SparseT M[MAX_SPARSE][LOG_SPARSE];	// 1 + ceil(log2(MAX_SP))
	SparseTable() {}
	void init(int n) {
		for (int i = 0; i < n; ++i) M[i][0] = i;
		for (int j = 1, p = 2, q = 1; p <= n; ++j, p <<= 1, q <<= 1)
			for (int i = 0; i + p - 1 < n; ++i) {
				int a = M[i][j - 1], b = M[i + q][j - 1];
				M[i][j] = A[a] <= A[b] ? a : b;
			}
	}
	SparseT query_val(int i, int j) { return A[query_idx(i, j)]; }
	int query_idx(int i, int j) {
		int k = log2(j - i + 1);
		int a = M[i][k], b = M[j + 1 - (1<<k)][k];
		return A[a] <= A[b] ? a : b;
	}
};

//
// Binary Search Tree
//
const int Nil = 0;
#define LT(t)  (T[T[t].l])
#define RT(t)  (T[T[t].r])
#define PAR(t) (T[T[t].p])
struct Bst {
	struct Node {
		int p, l, r, s, k;	// parent, left, right, size, key
		void init(int K) { k = K; p = l = r = Nil; s = 1; }
		void clear() { p = l = r = s = k = 0; }
	};
	int K[MAXK];
	Node T[MAXK + 1];
	int root, sz;
	int get(int t) { return K[T[t].k]; }
	int size() { return T[root].s; }
	void init(int n) { T[0].clear(); sz = 0; root = init_tree(0, n - 1); }
	int init_tree(int a, int b) {
		if (a > b) return Nil;
		int t = ++sz;
		if (a == b) { T[t].init(a); return t; }
		int m = (a + b) / 2;
		T[t].l = init_tree(a, m - 1);
		T[t].r = init_tree(m + 1, b);
		T[t].p = Nil, T[t].k = m, T[t].s = 1 + LT(t).s + RT(t).s;
		LT(t).p = t; RT(t).p = t;
		return t;
	}
	int find_kth(int k) { return find_kth_tree(k, root); }
	int find_kth_tree(int k, int t) {
		if (LT(t).s > k) return find_kth_tree(k, T[t].l);
		k -= LT(t).s;
		if (k == 0) return t;
		if (--k >= RT(t).s) return Nil;
		return find_kth_tree(k, T[t].r);
	}
	void remove(int t) {
		int x;
		if (T[t].l != Nil && T[t].r != Nil) {
			if (RT(t).s >= LT(t).s) for (x=T[t].r; T[x].l != Nil; x=T[x].l) ;
			else					for (x=T[t].l; T[x].r != Nil; x=T[x].r) ;
			T[t].k = T[x].k;
			t = x;
		}
		if (T[t].l == Nil && T[t].r == Nil) {
			if (T[t].p == Nil) { root = Nil; return; }
			if (PAR(t).l == t) PAR(t).l = Nil;
			else			   PAR(t).r = Nil;
		}
		else {
			x = T[t].l != Nil ? T[t].l : T[t].r;
			if (T[t].p == Nil) { T[root = x].p = Nil; return; }
			if (PAR(t).l == t) PAR(t).l = x;
			else			   PAR(t).r = x;
			T[x].p = T[t].p;
		}
		for (x = T[t].p; x != Nil; x = T[x].p) --T[x].s;
	}
};
<commit_msg>Expanded HashMap methods<commit_after>//
// Trie
//
struct Trie {
	struct Node {
		int ch[8];
		int n;
	};
	Node nodes[MAX_NODES];
	int sz;
	void init() { Zero(nodes); sz = 1; }
	int insert(const char *s) {
		int idx, cur = 0;
		for (; *s; ++s) {
			idx = toupper(s[i]) - 'A';
			if (! nodes[cur].ch[idx])
				nodes[cur].ch[idx] = sz++;
			cur = nodes[cur].ch[idx];
		}
		return ++nodes[cur].n;
	}
};

//
// Hash Map
//
struct HashT {
	int k, v;

	HashT() {}
	HashT(int K, int V): k(K), v(V) {}

	bool operator==(const HashT &x) const { return k == x.k; }
};
#define HASHB (1<<15)
#define HASHN 1000000
#define HASHT_SZ (sizeof(int))
#define HASHT_PTR(x) (reinterpret_cast<u8*>(&( (x).k )))
struct HashMap {
	HashT data[HASHN];
	int next[HASHN];
	int buckets[HASHB];
	int n;

	void init() { Neg(buckets); n = 0; }
	u32 fnv_hash(const u8 *p, int n) const {
		u32 h = 2166136261U;
		for (int i = 0; i < n; ++i) h = (h * 16777619U) ^ p[i];
		return h;
	}

	void add(HashT &h) {
		int b = fnv_hash(HASHT_PTR(h), HASHT_SZ) % HASHB;
		for (int i = buckets[b]; i >= 0; i = next[i])
			if (data[i] == h) return;
		next[n] = buckets[b], buckets[b] = n, data[n++] = h;
	}
	bool find(HashT &h) {
		int b = fnv_hash(HASHT_PTR(h), HASHT_SZ) % HASHB;
		for (int i = buckets[b]; i >= 0; i = next[i])
			if (data[i] == h) return true;
		return false;
	}

	// combines add/find
	HashT *add(HashT &h, bool &found) {
		int b = fnv_hash(HASHT_PTR(h), HASHT_SZ) % HASHB;
		for (int i = buckets[b]; i >= 0; i = next[i])
			if (data[i] == h) { found = true; return &data[i]; }
		found = false, next[n] = buckets[b], buckets[b] = n, data[n] = h;
		return &data[n++];
	}
};

//
// Binary Indexed Tree
//
struct Bit {
	BitT f[MAXBIT + 1];
	int n;
	void init(int N) { n=N; Clr(f); }
	void add(int i, BitT v) { while (i <= n) { f[i] += v; i += GetFS(i); } }
	BitT query(int i) { BitT r = 0; for (;i; ClrFS(i)) r += f[i]; return r; }
	BitT query(int from, int to) { return query(to) - query(from - 1); }
};

//
// Segment Tree
//
#define TreeIsLeaf (a == b)
#define TreeIsOut  (j < a || b < i)
#define TreeIsIn   (i <= a && b <= j)
#define TreeLeft   2*x, a, (a+b)/2
#define TreeRight  2*x+1, (a+b)/2+1, b

#define Tree  (T[x])
#define Left  (T[2*x])
#define Right (T[2*x+1])

#define LOGN 19  // 1 + ceil(log2(MAXN))
struct SegTreeH {
	struct Node {
		int i;  // some value
		int p;  // propagation
	};

	Node T[1 << LOGN];
	int n;

	void init(int N) { n = N; init(1, 0, n-1); }
	void init(int x, int a, int b) {
		Tree.i = Tree.p = -1;
		if (TreeIsLeaf) return;
		init(TreeLeft);
		init(TreeRight);
	}

	void propagate(int x, int a, int b) {
		if (Tree.p < 0) return;
		Tree.i = Tree.p;
		if (! TreeIsLeaf)
			Left.p = Right.p = Tree.p;
		Tree.p = -1;
	}

	void update(int i, int j, int v) { update(i, j, v, 1, 0, n-1); }
	void update(int i, int j, int v, int x, int a, int b) {
		propagate(x, a, b);
		if (TreeIsOut) return;
		if (TreeIsLeaf) { Tree.i = v; return; }

		if (TreeIsIn) {
			Tree.i = v;
			Left.p = Right.p = v;
			return;
		}
		update(i, j, v, TreeLeft);
		update(i, j, v, TreeRight);
		Tree.i = Right.i;
	}

	int query(int i, int j) { return query(i, j, 1, 0, n-1); }
	int query(int i, int j, int x, int a, int b) {
		if (TreeIsOut) return -1;
		propagate(x, a, b);
		if (TreeIsIn) return Tree.i;
		int q1 = query(i, j, TreeLeft);
		int q2 = query(i, j, TreeRight);
		return max(q1, q2);
	}

};

//
// R-Tree for 2D matrices
//
const int MAX_ROWS = MAXN;
const int MAX_COLS = MAXN;
const int MAX_H    = 19;   // 1 + ceil(log2(MAX_ROWS * MAX_COLS))
template <typename NT>
struct R2Tree {
	struct Node { NT v; };

	Node T[1 << MAX_H];
	NT	 M[MAX_ROWS][MAX_COLS];
	int  r, c;

	void init(int R, int C) { tree_init(1, 0, 0, r=R, c=C, 0); }
	void tree_init(int x, int r1, int c1, int r2, int c2, int o) {
		if (r1 == r2 && c1 == c2) {
			T[x].v = M[r1][c1];
			return;
		}

		int op = (o + 1) % 2;
		int lt = 2*x, rt = lt + 1;
		if ((o == 0 && c1 < c2) || r1 == r2) {
			int md = (c1 + c2) / 2;
			tree_init(lt, r1, c1, r2, md, op);
			tree_init(rt, r1, md + 1, r2, c2, op);
		}
		else {
			int md = (r1 + r2) / 2;
			tree_init(lt, r1, c1, md, c2, op);
			tree_init(rt, md + 1, c1, r2, c2, op);
		}
		T[x].v = max(T[lt].v, T[rt].v);
	}

	int qr1, qc1, qr2, qc2;
	NT get(int r1, int c1, int r2, int c2) {
		qr1 = r1, qc1 = c1, qr2 = r2, qc2 = c2;
		return tree_get(1, 0, 0, r, c, 0);
	}
	NT tree_get(int x, int r1, int c1, int r2, int c2, int o) {
		if (r1 >= qr1 && r2 <= qr2 && c1 >= qc1 && c2 <= qc2) return T[x].v;
		if (r1 > qr2 || r2 < qr1 || c1 > qc2 || c2 < qc1) return -1;

		int op = (o + 1) % 2;
		int lt = 2*x, rt = lt + 1;
		NT a, b;
		if ((o == 0 && c1 < c2) || r1 == r2) {
			int md = (c1 + c2) / 2;
			a = tree_get(lt, r1, c1, r2, md, op);
			b = tree_get(rt, r1, md + 1, r2, c2, op);
		}
		else {
			int md = (r1 + r2) / 2;
			a = tree_get(lt, r1, c1, md, c2, op);
			b = tree_get(rt, md + 1, c1, r2, c2, op);
		}
		return max(a, b);
	}
};

//
// Lowest Common Ancestor
//
struct LCA {
	int L[MAXN];        // L[i]: level of node i
	int A[MAXN][LOGN];  // A[i][j]: 2^j'th ancestor of i
	int n, h, lh;       // n, height, log(h)
	LCA() {}

	void init(int N, int H) { n=N, h=H; Neg(A); lh = log2(h); }
	void process() {
		// precond: A[i][0] is set for all i
		for (int j = 1, p = 2; p < h; ++j, p <<= 1)
			for (int i = 0; i < n; ++i)
				if (A[i][j-1] != -1)
					A[i][j] = A[ A[i][j-1] ][j-1];
	}
	int query_orig(int a, int b) {
		if (L[a] < L[b]) swap(a, b);

		for (int i = lh, p = 1 << lh; i >= 0; --i, p >>= 1)
			if (L[a] - p >= L[b]) a = A[a][i];
		if (a == b) return a;

		for (int i = lh; i >= 0; --i)
			if (A[a][i] != -1 && A[a][i] != A[b][i])
				a = A[a][i], b = A[b][i];
		return A[a][0];
	}
};

//
// Sparse Table
//
struct SparseTable {
	SparseT A[MAX_SPARSE];
	SparseT M[MAX_SPARSE][LOG_SPARSE];	// 1 + ceil(log2(MAX_SP))
	SparseTable() {}
	void init(int n) {
		for (int i = 0; i < n; ++i) M[i][0] = i;
		for (int j = 1, p = 2, q = 1; p <= n; ++j, p <<= 1, q <<= 1)
			for (int i = 0; i + p - 1 < n; ++i) {
				int a = M[i][j - 1], b = M[i + q][j - 1];
				M[i][j] = A[a] <= A[b] ? a : b;
			}
	}
	SparseT query_val(int i, int j) { return A[query_idx(i, j)]; }
	int query_idx(int i, int j) {
		int k = log2(j - i + 1);
		int a = M[i][k], b = M[j + 1 - (1<<k)][k];
		return A[a] <= A[b] ? a : b;
	}
};

//
// Binary Search Tree
//
const int Nil = 0;
#define LT(t)  (T[T[t].l])
#define RT(t)  (T[T[t].r])
#define PAR(t) (T[T[t].p])
struct Bst {
	struct Node {
		int p, l, r, s, k;	// parent, left, right, size, key
		void init(int K) { k = K; p = l = r = Nil; s = 1; }
		void clear() { p = l = r = s = k = 0; }
	};
	int K[MAXK];
	Node T[MAXK + 1];
	int root, sz;
	int get(int t) { return K[T[t].k]; }
	int size() { return T[root].s; }
	void init(int n) { T[0].clear(); sz = 0; root = init_tree(0, n - 1); }
	int init_tree(int a, int b) {
		if (a > b) return Nil;
		int t = ++sz;
		if (a == b) { T[t].init(a); return t; }
		int m = (a + b) / 2;
		T[t].l = init_tree(a, m - 1);
		T[t].r = init_tree(m + 1, b);
		T[t].p = Nil, T[t].k = m, T[t].s = 1 + LT(t).s + RT(t).s;
		LT(t).p = t; RT(t).p = t;
		return t;
	}
	int find_kth(int k) { return find_kth_tree(k, root); }
	int find_kth_tree(int k, int t) {
		if (LT(t).s > k) return find_kth_tree(k, T[t].l);
		k -= LT(t).s;
		if (k == 0) return t;
		if (--k >= RT(t).s) return Nil;
		return find_kth_tree(k, T[t].r);
	}
	void remove(int t) {
		int x;
		if (T[t].l != Nil && T[t].r != Nil) {
			if (RT(t).s >= LT(t).s) for (x=T[t].r; T[x].l != Nil; x=T[x].l) ;
			else					for (x=T[t].l; T[x].r != Nil; x=T[x].r) ;
			T[t].k = T[x].k;
			t = x;
		}
		if (T[t].l == Nil && T[t].r == Nil) {
			if (T[t].p == Nil) { root = Nil; return; }
			if (PAR(t).l == t) PAR(t).l = Nil;
			else			   PAR(t).r = Nil;
		}
		else {
			x = T[t].l != Nil ? T[t].l : T[t].r;
			if (T[t].p == Nil) { T[root = x].p = Nil; return; }
			if (PAR(t).l == t) PAR(t).l = x;
			else			   PAR(t).r = x;
			T[x].p = T[t].p;
		}
		for (x = T[t].p; x != Nil; x = T[x].p) --T[x].s;
	}
};
<|endoftext|>


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

#include "auth/AuthSupported.h"
#include "auth/KeyRing.h"
#include "common/ceph_argparse.h"
#include "common/safe_io.h"
#include "common/signal.h"
#include "common/version.h"
#include "common/config.h"
#include "common/common_init.h"
#include "common/errno.h"
#include "include/color.h"

#include <syslog.h>

/* Set foreground logging
 *
 * Forces the process to log only to stderr, overriding whatever was in the ceph.conf.
 *
 * TODO: make this configurable by a command line switch or environment variable, if users want
 * an unusual logging setup for their foreground process.
 */
void set_foreground_logging()
{
  free((void*)g_conf.log_file);
  g_conf.log_file = NULL;

  free((void*)g_conf.log_dir);
  g_conf.log_dir = NULL;

  free((void*)g_conf.log_sym_dir);
  g_conf.log_sym_dir = NULL;

  g_conf.log_sym_history = 0;

  g_conf.log_to_stderr = LOG_TO_STDERR_ALL;

  g_conf.log_to_syslog = false;

  g_conf.log_per_instance = false;
}

static void keyring_init(const char *filesearch)
{
  const char *filename = filesearch;
  string keyring_search = g_conf.keyring;
  string new_keyring;
  if (ceph_resolve_file_search(keyring_search, new_keyring)) {
    filename = new_keyring.c_str();
  }

  int ret = g_keyring.load(filename);

  if (g_conf.key && g_conf.key[0]) {
    string k = g_conf.key;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  } else if (g_conf.keyfile && g_conf.keyfile[0]) {
    char buf[100];
    int fd = ::open(g_conf.keyfile, O_RDONLY);
    if (fd < 0) {
      int err = errno;
      derr << "unable to open " << g_conf.keyfile << ": "
	   << cpp_strerror(err) << dendl;
      ceph_abort();
    }
    memset(buf, 0, sizeof(buf));
    int len = safe_read(fd, buf, sizeof(buf) - 1);
    if (len < 0) {
      derr << "unable to read key from " << g_conf.keyfile << ": "
	   << cpp_strerror(len) << dendl;
      TEMP_FAILURE_RETRY(::close(fd));
      ceph_abort();
    }
    TEMP_FAILURE_RETRY(::close(fd));

    buf[len] = 0;
    string k = buf;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  }

  if (ret) {
    derr << "keyring_init: failed to load " << filename << dendl;
    return;
  }
}

static void set_cv(const char ** key, const char * const val)
{
  free((void*)*key);
  *key = strdup(val);
}

void common_init(std::vector<const char*>& args, const char *module_type, int flags)
{
  bool force_fg_logging = false;

  if (flags & STARTUP_FLAG_DAEMON) {
    cout << TEXT_YELLOW << " ** WARNING: Ceph is still under heavy development, "
         << "and is only suitable for **" << TEXT_NORMAL << std::endl;
    cout << TEXT_YELLOW <<  " **          testing and review.  Do not trust it "
         << "with important data.       **" << TEXT_NORMAL << std::endl;

    // some daemon-specific defaults
    g_conf.daemonize = true;
    g_conf.log_to_stderr = LOG_TO_STDERR_SOME;
    set_cv(&g_conf.log_dir, "/var/log/ceph");
    set_cv(&g_conf.pid_file, "/var/run/ceph/$type.$id.pid");
  }
  else {
    g_conf.pid_file = 0;
  }

  parse_startup_config_options(args, module_type, flags, &force_fg_logging);

  if (g_conf.log_to_syslog || g_conf.clog_to_syslog) {
    closelog();
    // It's ok if g_conf.name is NULL here.
    openlog(g_conf.name, LOG_ODELAY | LOG_PID, LOG_USER);
  }

  if (force_fg_logging)
    set_foreground_logging();

  {
    // In the long term, it would be best to ensure that we read ceph.conf
    // before initializing dout(). For now, just force a reopen here with the
    // configuration we have just read.
    DoutLocker _dout_locker;
    _dout_open_log();
  }

  if (g_conf.daemonize)
    cout << ceph_version_to_string() << std::endl;

  parse_config_options(args);
  install_standard_sighandlers();

#ifdef HAVE_LIBTCMALLOC
  if (g_conf.tcmalloc_profiler_run && g_conf.tcmalloc_have) {
    char profile_name[PATH_MAX];
    sprintf(profile_name, "%s/%s", g_conf.log_dir, g_conf.name);
    char *val = new char[sizeof(int)*8+1];
    sprintf(val, "%i", g_conf.profiler_allocation_interval);
    setenv("HEAP_PROFILE_ALLOCATION_INTERVAL", val, g_conf.profiler_allocation_interval);
    sprintf(val, "%i", g_conf.profiler_highwater_interval);
    setenv("HEAP_PROFILE_INUSE_INTERVAL", val, g_conf.profiler_highwater_interval);
    generic_dout(0) << "turning on heap profiler with prefix " << profile_name << dendl;
    g_conf.profiler_start(profile_name);
  }
#endif //HAVE_LIBTCMALLOC

  if (flags & STARTUP_FLAG_INIT_KEYS)  {
    if (is_supported_auth(CEPH_AUTH_CEPHX))
      keyring_init(g_conf.keyring);
  }
}

<commit_msg>dout: Reopen dout after parsing all config opts<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "auth/AuthSupported.h"
#include "auth/KeyRing.h"
#include "common/ceph_argparse.h"
#include "common/safe_io.h"
#include "common/signal.h"
#include "common/version.h"
#include "common/config.h"
#include "common/common_init.h"
#include "common/errno.h"
#include "include/color.h"

#include <syslog.h>

/* Set foreground logging
 *
 * Forces the process to log only to stderr, overriding whatever was in the ceph.conf.
 *
 * TODO: make this configurable by a command line switch or environment variable, if users want
 * an unusual logging setup for their foreground process.
 */
void set_foreground_logging()
{
  free((void*)g_conf.log_file);
  g_conf.log_file = NULL;

  free((void*)g_conf.log_dir);
  g_conf.log_dir = NULL;

  free((void*)g_conf.log_sym_dir);
  g_conf.log_sym_dir = NULL;

  g_conf.log_sym_history = 0;

  g_conf.log_to_stderr = LOG_TO_STDERR_ALL;

  g_conf.log_to_syslog = false;

  g_conf.log_per_instance = false;
}

static void keyring_init(const char *filesearch)
{
  const char *filename = filesearch;
  string keyring_search = g_conf.keyring;
  string new_keyring;
  if (ceph_resolve_file_search(keyring_search, new_keyring)) {
    filename = new_keyring.c_str();
  }

  int ret = g_keyring.load(filename);

  if (g_conf.key && g_conf.key[0]) {
    string k = g_conf.key;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  } else if (g_conf.keyfile && g_conf.keyfile[0]) {
    char buf[100];
    int fd = ::open(g_conf.keyfile, O_RDONLY);
    if (fd < 0) {
      int err = errno;
      derr << "unable to open " << g_conf.keyfile << ": "
	   << cpp_strerror(err) << dendl;
      ceph_abort();
    }
    memset(buf, 0, sizeof(buf));
    int len = safe_read(fd, buf, sizeof(buf) - 1);
    if (len < 0) {
      derr << "unable to read key from " << g_conf.keyfile << ": "
	   << cpp_strerror(len) << dendl;
      TEMP_FAILURE_RETRY(::close(fd));
      ceph_abort();
    }
    TEMP_FAILURE_RETRY(::close(fd));

    buf[len] = 0;
    string k = buf;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  }

  if (ret) {
    derr << "keyring_init: failed to load " << filename << dendl;
    return;
  }
}

static void set_cv(const char ** key, const char * const val)
{
  free((void*)*key);
  *key = strdup(val);
}

void common_init(std::vector<const char*>& args, const char *module_type, int flags)
{
  bool force_fg_logging = false;

  if (flags & STARTUP_FLAG_DAEMON) {
    cout << TEXT_YELLOW << " ** WARNING: Ceph is still under heavy development, "
         << "and is only suitable for **" << TEXT_NORMAL << std::endl;
    cout << TEXT_YELLOW <<  " **          testing and review.  Do not trust it "
         << "with important data.       **" << TEXT_NORMAL << std::endl;

    // some daemon-specific defaults
    g_conf.daemonize = true;
    g_conf.log_to_stderr = LOG_TO_STDERR_SOME;
    set_cv(&g_conf.log_dir, "/var/log/ceph");
    set_cv(&g_conf.pid_file, "/var/run/ceph/$type.$id.pid");
  }
  else {
    g_conf.pid_file = 0;
  }

  parse_startup_config_options(args, module_type, flags, &force_fg_logging);

  if (g_conf.log_to_syslog || g_conf.clog_to_syslog) {
    closelog();
    // It's ok if g_conf.name is NULL here.
    openlog(g_conf.name, LOG_ODELAY | LOG_PID, LOG_USER);
  }

  if (force_fg_logging)
    set_foreground_logging();

  if (g_conf.daemonize)
    cout << ceph_version_to_string() << std::endl;

  parse_config_options(args);

  {
    // In the long term, it would be best to ensure that we read ceph.conf
    // before initializing dout(). For now, just force a reopen here with the
    // configuration we have just read.
    DoutLocker _dout_locker;
    _dout_open_log();
  }

  install_standard_sighandlers();

#ifdef HAVE_LIBTCMALLOC
  if (g_conf.tcmalloc_profiler_run && g_conf.tcmalloc_have) {
    char profile_name[PATH_MAX];
    sprintf(profile_name, "%s/%s", g_conf.log_dir, g_conf.name);
    char *val = new char[sizeof(int)*8+1];
    sprintf(val, "%i", g_conf.profiler_allocation_interval);
    setenv("HEAP_PROFILE_ALLOCATION_INTERVAL", val, g_conf.profiler_allocation_interval);
    sprintf(val, "%i", g_conf.profiler_highwater_interval);
    setenv("HEAP_PROFILE_INUSE_INTERVAL", val, g_conf.profiler_highwater_interval);
    generic_dout(0) << "turning on heap profiler with prefix " << profile_name << dendl;
    g_conf.profiler_start(profile_name);
  }
#endif //HAVE_LIBTCMALLOC

  if (flags & STARTUP_FLAG_INIT_KEYS)  {
    if (is_supported_auth(CEPH_AUTH_CEPHX))
      keyring_init(g_conf.keyring);
  }
}

<|endoftext|>


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

#include "common/simple_spin.h"

#include <stdio.h>
#include <stdint.h>
#include <pthread.h>

uint32_t bar = 13;
uint32_t *foo = &bar;

void simple_spin_lock(simple_spinlock_t *lock)
{
  while(1) {
    __sync_synchronize();
    uint32_t oldval = *lock;
    if (oldval == 0) {
      if (__sync_bool_compare_and_swap(lock, 0, 1))
	return;
    }
    // delay
    for (int i = 0; i < 100000; i++) {
      *foo = (*foo * 33) + 17;
    }
  }
}

void simple_spin_unlock(simple_spinlock_t *lock)
{
  __sync_bool_compare_and_swap(lock, 1, 0);
}
<commit_msg>simple_spin: fix linker error<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2011 New Dream Network
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "common/simple_spin.h"

#include <stdio.h>
#include <stdint.h>
#include <pthread.h>

void simple_spin_lock(simple_spinlock_t *lock)
{
  static uint32_t bar = 13;
  static uint32_t *foo = &bar;

  while(1) {
    __sync_synchronize();
    uint32_t oldval = *lock;
    if (oldval == 0) {
      if (__sync_bool_compare_and_swap(lock, 0, 1))
	return;
    }
    // delay
    for (int i = 0; i < 100000; i++) {
      *foo = (*foo * 33) + 17;
    }
  }
}

void simple_spin_unlock(simple_spinlock_t *lock)
{
  __sync_bool_compare_and_swap(lock, 1, 0);
}
<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2021, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "framesetexportlist.h"
#include "models/common/errorlist.h"

namespace UnTech {
namespace MetaSprite {
namespace Compiler {

namespace MS = UnTech::MetaSprite::MetaSprite;

using ExportName = FrameSetExportOrder::ExportName;

static std::vector<AnimationListEntry>
processAnimations(const MS::FrameSet& frameSet, const NamedList<ExportName>& animations)
{
    std::vector<AnimationListEntry> ret;
    ret.reserve(animations.size());

    for (const auto& en : animations) {
        if (auto ani = frameSet.animations.find(en.name)) {
            ret.push_back({ &*ani, false, false });
        }
        else {
            bool success = false;

            for (const auto& alt : en.alternatives) {
                if (auto altAni = frameSet.animations.find(alt.name)) {
                    ret.push_back({ &*altAni, alt.hFlip, alt.vFlip });

                    success = true;
                    break;
                }
            }
            assert(success);
        }
    }

    // Include the animations referenced in the nextAnimation field

    // Must use an old-style for loop, ret is resized inside this loop.
    for (unsigned toTestIndex = 0; toTestIndex < ret.size(); toTestIndex++) {
        const auto& ani = ret[toTestIndex];

        if (ani.animation->oneShot == false && ani.animation->nextAnimation.isValid()) {
            const idstring& nextAnimation = ani.animation->nextAnimation;

            auto a = frameSet.animations.find(nextAnimation);
            assert(a);

            AnimationListEntry toAdd = { &*a, ani.hFlip, ani.vFlip };

            auto it = std::find(ret.begin(), ret.end(), toAdd);
            if (it == ret.end()) {
                ret.push_back(toAdd);
            }
        }
    }

    return ret;
}

static std::vector<FrameListEntry>
processStillFrames(const MS::FrameSet& frameSet,
                   const NamedList<ExportName>& stillFrames,
                   const std::vector<AnimationListEntry>& animations)
{
    std::vector<FrameListEntry> ret;
    ret.reserve(stillFrames.size());

    for (const auto& en : stillFrames) {
        if (const auto frame = frameSet.frames.find(en.name)) {
            ret.push_back({ &*frame, false, false });
        }
        else {
            bool success = false;

            for (const auto& alt : en.alternatives) {
                if (auto altFrame = frameSet.frames.find(alt.name)) {
                    ret.push_back({ &*altFrame, alt.hFlip, alt.vFlip });

                    success = true;
                    break;
                }
            }
            assert(success);
        }
    }

    // Add frames from animation.
    // Ensure that the frames added are unique.

    for (const AnimationListEntry& ani : animations) {
        for (const auto& aFrame : ani.animation->frames) {
            const auto& frameRef = aFrame.frame;

            auto frame = frameSet.frames.find(frameRef.name);
            assert(frame);

            FrameListEntry e = { &*frame,
                                 static_cast<bool>(frameRef.hFlip ^ ani.hFlip),
                                 static_cast<bool>(frameRef.vFlip ^ ani.vFlip) };

            auto it = std::find(ret.begin(), ret.end(), e);
            if (it == ret.end()) {
                // new entry
                ret.push_back(e);
            }
        }
    }

    return ret;
}

FrameSetExportList buildExportList(const MS::FrameSet& frameSet, const FrameSetExportOrder& exportOrder)
{
    const auto animations = processAnimations(frameSet, exportOrder.animations);

    return {
        frameSet,
        exportOrder,
        std::move(animations),
        processStillFrames(frameSet, exportOrder.stillFrames, animations)
    };
}

bool validate(const FrameSetExportList& input, ErrorList& err)
{
    bool valid = true;

    if (input.animations.size() > MAX_EXPORT_NAMES) {
        err.addErrorString("Too many animations (", input.animations.size(), ", max ", MAX_EXPORT_NAMES, ")");
        valid = false;
    }
    if (input.frames.size() > MAX_EXPORT_NAMES) {
        err.addErrorString("Too many frames (", input.frames.size(), ", max ", MAX_EXPORT_NAMES, ")");
        valid = false;
    }

    return valid;
}

}
}
}
<commit_msg>Fix use after move in buildExportList<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2021, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "framesetexportlist.h"
#include "models/common/errorlist.h"

namespace UnTech {
namespace MetaSprite {
namespace Compiler {

namespace MS = UnTech::MetaSprite::MetaSprite;

using ExportName = FrameSetExportOrder::ExportName;

static std::vector<AnimationListEntry>
processAnimations(const MS::FrameSet& frameSet, const NamedList<ExportName>& animations)
{
    std::vector<AnimationListEntry> ret;
    ret.reserve(animations.size());

    for (const auto& en : animations) {
        if (auto ani = frameSet.animations.find(en.name)) {
            ret.push_back({ &*ani, false, false });
        }
        else {
            bool success = false;

            for (const auto& alt : en.alternatives) {
                if (auto altAni = frameSet.animations.find(alt.name)) {
                    ret.push_back({ &*altAni, alt.hFlip, alt.vFlip });

                    success = true;
                    break;
                }
            }
            assert(success);
        }
    }

    // Include the animations referenced in the nextAnimation field

    // Must use an old-style for loop, ret is resized inside this loop.
    for (unsigned toTestIndex = 0; toTestIndex < ret.size(); toTestIndex++) {
        const auto& ani = ret[toTestIndex];

        if (ani.animation->oneShot == false && ani.animation->nextAnimation.isValid()) {
            const idstring& nextAnimation = ani.animation->nextAnimation;

            auto a = frameSet.animations.find(nextAnimation);
            assert(a);

            AnimationListEntry toAdd = { &*a, ani.hFlip, ani.vFlip };

            auto it = std::find(ret.begin(), ret.end(), toAdd);
            if (it == ret.end()) {
                ret.push_back(toAdd);
            }
        }
    }

    return ret;
}

static std::vector<FrameListEntry>
processStillFrames(const MS::FrameSet& frameSet,
                   const NamedList<ExportName>& stillFrames,
                   const std::vector<AnimationListEntry>& animations)
{
    std::vector<FrameListEntry> ret;
    ret.reserve(stillFrames.size());

    for (const auto& en : stillFrames) {
        if (const auto frame = frameSet.frames.find(en.name)) {
            ret.push_back({ &*frame, false, false });
        }
        else {
            bool success = false;

            for (const auto& alt : en.alternatives) {
                if (auto altFrame = frameSet.frames.find(alt.name)) {
                    ret.push_back({ &*altFrame, alt.hFlip, alt.vFlip });

                    success = true;
                    break;
                }
            }
            assert(success);
        }
    }

    // Add frames from animation.
    // Ensure that the frames added are unique.

    for (const AnimationListEntry& ani : animations) {
        for (const auto& aFrame : ani.animation->frames) {
            const auto& frameRef = aFrame.frame;

            auto frame = frameSet.frames.find(frameRef.name);
            assert(frame);

            FrameListEntry e = { &*frame,
                                 static_cast<bool>(frameRef.hFlip ^ ani.hFlip),
                                 static_cast<bool>(frameRef.vFlip ^ ani.vFlip) };

            auto it = std::find(ret.begin(), ret.end(), e);
            if (it == ret.end()) {
                // new entry
                ret.push_back(e);
            }
        }
    }

    return ret;
}

FrameSetExportList buildExportList(const MS::FrameSet& frameSet, const FrameSetExportOrder& exportOrder)
{
    const auto animations = processAnimations(frameSet, exportOrder.animations);
    const auto frames = processStillFrames(frameSet, exportOrder.stillFrames, animations);

    return {
        frameSet,
        exportOrder,
        std::move(animations),
        std::move(frames),
    };
}

bool validate(const FrameSetExportList& input, ErrorList& err)
{
    bool valid = true;

    if (input.animations.size() > MAX_EXPORT_NAMES) {
        err.addErrorString("Too many animations (", input.animations.size(), ", max ", MAX_EXPORT_NAMES, ")");
        valid = false;
    }
    if (input.frames.size() > MAX_EXPORT_NAMES) {
        err.addErrorString("Too many frames (", input.frames.size(), ", max ", MAX_EXPORT_NAMES, ")");
        valid = false;
    }

    return valid;
}

}
}
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013-2015 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.
 *
 ****************************************************************************/

/**
 * @file MulticopterLandDetector.cpp
 * Land detection algorithm for multicopters
 *
 * @author Johan Jansen <jnsn.johan@gmail.com>
 * @author Morten Lysgaard <morten@lysgaard.no>
 */

#include "MulticopterLandDetector.h"

#include <cmath>
#include <drivers/drv_hrt.h>
#include <mathlib/mathlib.h>

MulticopterLandDetector::MulticopterLandDetector() : LandDetector(),
	_paramHandle(),
	_params(),
	_vehicleGlobalPositionSub(-1),
	_vehicleStatusSub(-1),
	_actuatorsSub(-1),
	_armingSub(-1),
	_parameterSub(-1),
    _attitudeSub(-1),
	_vehicleGlobalPosition({}),
	_vehicleStatus({}),
	_actuators({}),
	_arming({}),
    _vehicleAttitude({}),
	_landTimer(0)
{
	_paramHandle.maxRotation = param_find("LNDMC_ROT_MAX");
	_paramHandle.maxVelocity = param_find("LNDMC_XY_VEL_MAX");
	_paramHandle.maxClimbRate = param_find("LNDMC_Z_VEL_MAX");
	_paramHandle.maxThrottle = param_find("LNDMC_THR_MAX");
}

void MulticopterLandDetector::initialize()
{
	// subscribe to position, attitude, arming and velocity changes
	_vehicleGlobalPositionSub = orb_subscribe(ORB_ID(vehicle_global_position));
	_attitudeSub = orb_subscribe(ORB_ID(vehicle_attitude));
	_vehicleStatusSub = orb_subscribe(ORB_ID(vehicle_status));
	_actuatorsSub = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
	_armingSub = orb_subscribe(ORB_ID(actuator_armed));
	_parameterSub = orb_subscribe(ORB_ID(parameter_update));

	// download parameters
	updateParameterCache(true);
}

void MulticopterLandDetector::updateSubscriptions()
{
	orb_update(ORB_ID(vehicle_global_position), _vehicleGlobalPositionSub, &_vehicleGlobalPosition);
	orb_update(ORB_ID(vehicle_attitude), _attitudeSub, &_vehicleAttitude);
	orb_update(ORB_ID(vehicle_status), _vehicleStatusSub, &_vehicleStatus);
	orb_update(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, _actuatorsSub, &_actuators);
	orb_update(ORB_ID(actuator_armed), _armingSub, &_arming);
}

bool MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	// only trigger flight conditions if we are armed
	if (!_arming.armed) {
		return true;
	}

	const uint64_t now = hrt_absolute_time();

	// check if we are moving vertically
	bool verticalMovement = fabsf(_vehicleGlobalPosition.vel_d) > _params.maxClimbRate;

	// check if we are moving horizontally
	bool horizontalMovement = sqrtf(_vehicleGlobalPosition.vel_n * _vehicleGlobalPosition.vel_n
					+ _vehicleGlobalPosition.vel_e * _vehicleGlobalPosition.vel_e) > _params.maxVelocity
					&& _vehicleStatus.condition_global_position_valid;

	// next look if all rotation angles are not moving
	bool rotating = fabsf(_vehicleAttitude.rollspeed)  > _params.maxRotation ||
				    fabsf(_vehicleAttitude.pitchspeed) > _params.maxRotation ||
        			fabsf(_vehicleAttitude.yawspeed)   > _params.maxRotation;

	// check if thrust output is minimal (about half of default)
	bool minimalThrust = _actuators.control[3] <= _params.maxThrottle;

	if (verticalMovement || rotating || !minimalThrust || horizontalMovement) {
		// sensed movement, so reset the land detector
		_landTimer = now;
		return false;
	}

	return now - _landTimer > LAND_DETECTOR_TRIGGER_TIME;
}

void MulticopterLandDetector::updateParameterCache(const bool force)
{
	bool updated;
	parameter_update_s paramUpdate;

	orb_check(_parameterSub, &updated);

	if (updated) {
		orb_copy(ORB_ID(parameter_update), _parameterSub, &paramUpdate);
	}

	if (updated || force) {
		param_get(_paramHandle.maxClimbRate, &_params.maxClimbRate);
		param_get(_paramHandle.maxVelocity, &_params.maxVelocity);
		param_get(_paramHandle.maxRotation, &_params.maxRotation);
		_params.maxRotation = math::radians(_params.maxRotation);
		param_get(_paramHandle.maxThrottle, &_params.maxThrottle);
	}
}
<commit_msg>MC land detector: If no position information is available, rely on the armed state exclusively to infer the landed condition.<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013-2015 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.
 *
 ****************************************************************************/

/**
 * @file MulticopterLandDetector.cpp
 * Land detection algorithm for multicopters
 *
 * @author Johan Jansen <jnsn.johan@gmail.com>
 * @author Morten Lysgaard <morten@lysgaard.no>
 */

#include "MulticopterLandDetector.h"

#include <cmath>
#include <drivers/drv_hrt.h>
#include <mathlib/mathlib.h>

MulticopterLandDetector::MulticopterLandDetector() : LandDetector(),
	_paramHandle(),
	_params(),
	_vehicleGlobalPositionSub(-1),
	_vehicleStatusSub(-1),
	_actuatorsSub(-1),
	_armingSub(-1),
	_parameterSub(-1),
    _attitudeSub(-1),
	_vehicleGlobalPosition({}),
	_vehicleStatus({}),
	_actuators({}),
	_arming({}),
    _vehicleAttitude({}),
	_landTimer(0)
{
	_paramHandle.maxRotation = param_find("LNDMC_ROT_MAX");
	_paramHandle.maxVelocity = param_find("LNDMC_XY_VEL_MAX");
	_paramHandle.maxClimbRate = param_find("LNDMC_Z_VEL_MAX");
	_paramHandle.maxThrottle = param_find("LNDMC_THR_MAX");
}

void MulticopterLandDetector::initialize()
{
	// subscribe to position, attitude, arming and velocity changes
	_vehicleGlobalPositionSub = orb_subscribe(ORB_ID(vehicle_global_position));
	_attitudeSub = orb_subscribe(ORB_ID(vehicle_attitude));
	_vehicleStatusSub = orb_subscribe(ORB_ID(vehicle_status));
	_actuatorsSub = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
	_armingSub = orb_subscribe(ORB_ID(actuator_armed));
	_parameterSub = orb_subscribe(ORB_ID(parameter_update));

	// download parameters
	updateParameterCache(true);
}

void MulticopterLandDetector::updateSubscriptions()
{
	orb_update(ORB_ID(vehicle_global_position), _vehicleGlobalPositionSub, &_vehicleGlobalPosition);
	orb_update(ORB_ID(vehicle_attitude), _attitudeSub, &_vehicleAttitude);
	orb_update(ORB_ID(vehicle_status), _vehicleStatusSub, &_vehicleStatus);
	orb_update(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, _actuatorsSub, &_actuators);
	orb_update(ORB_ID(actuator_armed), _armingSub, &_arming);
}

bool MulticopterLandDetector::update()
{
	// first poll for new data from our subscriptions
	updateSubscriptions();

	// only trigger flight conditions if we are armed
	if (!_arming.armed) {
		return true;
	}

	// return status based on armed state if no position lock is available
	if (_vehicleGlobalPosition.timestamp == 0 ||
		hrt_elapsed_time(&_vehicleGlobalPosition.timestamp) > 500000) {

		// no position lock - not landed if armed
		return !_arming.armed;
	}

	const uint64_t now = hrt_absolute_time();

	// check if we are moving vertically
	bool verticalMovement = fabsf(_vehicleGlobalPosition.vel_d) > _params.maxClimbRate;

	// check if we are moving horizontally
	bool horizontalMovement = sqrtf(_vehicleGlobalPosition.vel_n * _vehicleGlobalPosition.vel_n
					+ _vehicleGlobalPosition.vel_e * _vehicleGlobalPosition.vel_e) > _params.maxVelocity
					&& _vehicleStatus.condition_global_position_valid;

	// next look if all rotation angles are not moving
	bool rotating = fabsf(_vehicleAttitude.rollspeed)  > _params.maxRotation ||
				    fabsf(_vehicleAttitude.pitchspeed) > _params.maxRotation ||
        			fabsf(_vehicleAttitude.yawspeed)   > _params.maxRotation;

	// check if thrust output is minimal (about half of default)
	bool minimalThrust = _actuators.control[3] <= _params.maxThrottle;

	if (verticalMovement || rotating || !minimalThrust || horizontalMovement) {
		// sensed movement, so reset the land detector
		_landTimer = now;
		return false;
	}

	return now - _landTimer > LAND_DETECTOR_TRIGGER_TIME;
}

void MulticopterLandDetector::updateParameterCache(const bool force)
{
	bool updated;
	parameter_update_s paramUpdate;

	orb_check(_parameterSub, &updated);

	if (updated) {
		orb_copy(ORB_ID(parameter_update), _parameterSub, &paramUpdate);
	}

	if (updated || force) {
		param_get(_paramHandle.maxClimbRate, &_params.maxClimbRate);
		param_get(_paramHandle.maxVelocity, &_params.maxVelocity);
		param_get(_paramHandle.maxRotation, &_params.maxRotation);
		_params.maxRotation = math::radians(_params.maxRotation);
		param_get(_paramHandle.maxThrottle, &_params.maxThrottle);
	}
}
<|endoftext|>