<commit_before>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <tuple>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/check_backward.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

using Arrays = std::vector<Array>;
using Fprop = std::function<std::vector<Array>(const std::vector<Array>&)>;

/*
Arrays IncorrectBackwardUnaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = lhs_node->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [](const Array& gout) { return gout * gout; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("incorrect_unary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

Arrays IncorrectBackwardBinaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];

    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad() || rhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = std::max(lhs_node->rank(), rhs_node->rank());
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node, rhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [rhs](const Array& gout) { return gout + rhs; } : empty_func;
        auto rhs_func = rhs.requires_grad() ? [lhs](const Array& gout) { return gout + lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func, rhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("incorrect_binary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

class CheckBackwardBaseTest : public ::testing::Test {
protected:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) const {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckBaseBackwardComputation(bool expect_correct, Fprop fprop, const Arrays& inputs, const Arrays& grad_outputs, const Arrays& eps,
                                      double atol, double rtol) {
        if (!expect_correct && std::any_of(inputs.begin(), inputs.end(), [](const Array& input) { return input.requires_grad(); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol), "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
        }
    }
};

class CheckBackwardUnaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<bool> {
protected:
    void SetUp() override { requires_grad = GetParam(); }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data, const T* grad_output_data,
                                  const T* eps_data, double atol, double rtol) {
        Arrays inputs{MakeArray(shape, input_data)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data)};
        inputs[0].set_requires_grad(requires_grad);  // parameterized by test
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol);
    }

private:
    bool requires_grad;
};

class CheckBackwardBinaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<std::tuple<bool, bool>> {
protected:
    void SetUp() override { requires_grads = {std::get<0>(GetParam()), std::get<1>(GetParam())}; }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data1, const T* input_data2,
                                  const T* grad_output_data, const T* eps_data1, const T* eps_data2, double atol, double rtol) {
        Arrays inputs{MakeArray(shape, input_data1), MakeArray(shape, input_data2)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
        inputs[0].set_requires_grad(requires_grads[0]);  // parameterized by test
        inputs[1].set_requires_grad(requires_grads[1]);
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol);
    }

private:
    std::vector<bool> requires_grads;
};

TEST_P(CheckBackwardUnaryTest, CorrectBackward) {
    float input_data[]{1.f, 2.f, 3.f};
    float grad_output_data[]{0.f, -2.f, 3.f};
    float eps_data[]{1.f, 2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4);
}

TEST_P(CheckBackwardUnaryTest, IncorrectBackward) {
    float input_data[]{-2.f, 3.f, 1.f};
    float grad_output_data[]{0.f, -2.f, 1.f};
    float eps_data[]{1.f, 2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardUnaryFunc, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4);
}

TEST_P(CheckBackwardBinaryTest, CorrectBackward) {
    float input_data1[]{1.f, 2.f, 3.f};
    float input_data2[]{0.f, 1.f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.f};
    float eps_data2[]{3.f, -2.f, 3.f};
    float grad_output_data[]{1.f, -2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[1]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2, 1e-5, 1e-4);
}

TEST_P(CheckBackwardBinaryTest, IncorrectBackward) {
    float input_data1[]{3.f, -2.f, 1.f};
    float input_data2[]{0.f, 1.4f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.8f};
    float eps_data2[]{3.f, -2.f, -3.f};
    float grad_output_data[]{4.f, -2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardBinaryFunc, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2,
                             1e-5, 1e-4);
}

INSTANTIATE_TEST_CASE_P(ForEachSingleSetRequiresGrad, CheckBackwardUnaryTest, ::testing::Bool());
INSTANTIATE_TEST_CASE_P(ForEachCombinedSetRequiresGrad, CheckBackwardBinaryTest, ::testing::Combine(::testing::Bool(), ::testing::Bool()));
*/

}  // namespace
}  // namespace xchainer
<commit_msg>Pass all CheckBackward with correct backward functions<commit_after>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <tuple>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/check_backward.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

using Arrays = std::vector<Array>;
using Fprop = std::function<std::vector<Array>(const std::vector<Array>&)>;

/*
Arrays IncorrectBackwardUnaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = lhs_node->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [](const Array& gout) { return gout * gout; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("incorrect_unary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

Arrays IncorrectBackwardBinaryFunc(const Arrays& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];

    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad() || rhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = std::max(lhs_node->rank(), rhs_node->rank());
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node, rhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [rhs](const Array& gout) { return gout + rhs; } : empty_func;
        auto rhs_func = rhs.requires_grad() ? [lhs](const Array& gout) { return gout + lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func, rhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("incorrect_binary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}
*/

class CheckBackwardBaseTest : public ::testing::Test {
protected:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) const {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckBaseBackwardComputation(bool expect_correct, Fprop fprop, const Arrays& inputs, const Arrays& grad_outputs, const Arrays& eps,
                                      double atol, double rtol) {
        if (!expect_correct && std::any_of(inputs.begin(), inputs.end(), [](const Array& input) { return input.requires_grad(); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol), "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
        }
    }
};

class CheckBackwardUnaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<bool> {
protected:
    void SetUp() override { requires_grad = GetParam(); }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data, const T* grad_output_data,
                                  const T* eps_data, double atol, double rtol) {
        Arrays inputs{MakeArray(shape, input_data)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data)};
        inputs[0].set_requires_grad(requires_grad);  // parameterized by test
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol);
    }

private:
    bool requires_grad;
};

class CheckBackwardBinaryTest : public CheckBackwardBaseTest, public ::testing::WithParamInterface<std::tuple<bool, bool>> {
protected:
    void SetUp() override { requires_grads = {std::get<0>(GetParam()), std::get<1>(GetParam())}; }

    template <typename T>
    void CheckBackwardComputation(bool expect_correct, Fprop fprop, const Shape& shape, const T* input_data1, const T* input_data2,
                                  const T* grad_output_data, const T* eps_data1, const T* eps_data2, double atol, double rtol) {
        Arrays inputs{MakeArray(shape, input_data1), MakeArray(shape, input_data2)};
        Arrays grad_outputs{MakeArray(shape, grad_output_data)};
        Arrays eps{MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
        inputs[0].set_requires_grad(requires_grads[0]);  // parameterized by test
        inputs[1].set_requires_grad(requires_grads[1]);
        CheckBaseBackwardComputation(expect_correct, fprop, inputs, grad_outputs, eps, atol, rtol);
    }

private:
    std::vector<bool> requires_grads;
};

TEST_P(CheckBackwardUnaryTest, CorrectBackward) {
    float input_data[]{1.f, 2.f, 3.f};
    float grad_output_data[]{0.f, -2.f, 3.f};
    float eps_data[]{1.f, 2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4);
}

/*
TEST_P(CheckBackwardUnaryTest, IncorrectBackward) {
    float input_data[]{-2.f, 3.f, 1.f};
    float grad_output_data[]{0.f, -2.f, 1.f};
    float eps_data[]{1.f, 2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardUnaryFunc, {1, 3}, input_data, grad_output_data, eps_data, 1e-5, 1e-4);
}
*/

TEST_P(CheckBackwardBinaryTest, CorrectBackward) {
    float input_data1[]{1.f, 2.f, 3.f};
    float input_data2[]{0.f, 1.f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.f};
    float eps_data2[]{3.f, -2.f, 3.f};
    float grad_output_data[]{1.f, -2.f, 3.f};
    Fprop fprop = [](const Arrays& inputs) -> Arrays { return {inputs[0] * inputs[1]}; };
    CheckBackwardComputation(true, fprop, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2, 1e-5, 1e-4);
}

/*
TEST_P(CheckBackwardBinaryTest, IncorrectBackward) {
    float input_data1[]{3.f, -2.f, 1.f};
    float input_data2[]{0.f, 1.4f, 2.f};
    float eps_data1[]{1.f, 2.f, 3.8f};
    float eps_data2[]{3.f, -2.f, -3.f};
    float grad_output_data[]{4.f, -2.f, 3.f};
    CheckBackwardComputation(false, &IncorrectBackwardBinaryFunc, {1, 3}, input_data1, input_data2, grad_output_data, eps_data1, eps_data2,
                             1e-5, 1e-4);
}
*/

INSTANTIATE_TEST_CASE_P(ForEachSingleSetRequiresGrad, CheckBackwardUnaryTest, ::testing::Bool());
INSTANTIATE_TEST_CASE_P(ForEachCombinedSetRequiresGrad, CheckBackwardBinaryTest, ::testing::Combine(::testing::Bool(), ::testing::Bool()));

}  // namespace
}  // namespace xchainer
<|endoftext|>


<commit_before>#include "xchainer/routines/logic.h"

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <limits>
#include <string>
#include <vector>

#include <gtest/gtest.h>
#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/device_id.h"
#include "xchainer/dtype.h"
#include "xchainer/testing/array.h"
#include "xchainer/testing/array_check.h"
#include "xchainer/testing/device_session.h"

namespace xchainer {
namespace {

class LogicTest : public ::testing::TestWithParam<std::string> {
protected:
    void SetUp() override {
        const std::string& backend_name = GetParam();
        device_session_.emplace(DeviceId{backend_name, 0});
    }

    void TearDown() override { device_session_.reset(); }

private:
    nonstd::optional<testing::DeviceSession> device_session_;
};

TEST_P(LogicTest, Equal) {
    using T = float;

    struct Param {
        T a;
        T b;
        bool e;
    };

    std::vector<Param> data = {{1.0f, 1.0f, true},
                               {1.0f, -1.0f, false},
                               {2.0f, 3.0f, false},
                               {1.0f, std::nanf(""), false},
                               {std::nanf(""), std::nanf(""), false},
                               {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), true},
                               {0.0f, -0.0f, true}};
    std::vector<T> a_data;
    std::vector<T> b_data;
    std::vector<bool> e_data;
    std::transform(data.begin(), data.end(), std::back_inserter(a_data), [](const auto& param) { return param.a; });
    std::transform(data.begin(), data.end(), std::back_inserter(b_data), [](const auto& param) { return param.b; });
    std::transform(data.begin(), data.end(), std::back_inserter(e_data), [](const auto& param) { return param.e; });
    Shape shape{static_cast<int64_t>(data.size())};
    Array a = testing::BuildArray(shape).WithData<T>(a_data.begin(), a_data.end());
    Array b = testing::BuildArray(shape).WithData<T>(b_data.begin(), b_data.end());
    Array e = testing::BuildArray(shape).WithData<bool>(e_data.begin(), e_data.end());
    Array c = Equal(a, b);

    ASSERT_EQ(c.dtype(), Dtype::kBool);
    EXPECT_TRUE(c.IsContiguous());
    testing::ExpectEqual<bool>(e, c);
}

INSTANTIATE_TEST_CASE_P(
        ForEachBackend,
        LogicTest,
        ::testing::Values(
#ifdef XCHAINER_ENABLE_CUDA
                std::string{"cuda"},
#endif  // XCHAINER_ENABLE_CUDA
                std::string{"native"}));

}  // namespace
}  // namespace xchainer
<commit_msg>Add Equal routine test with broadcasting<commit_after>#include "xchainer/routines/logic.h"

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <limits>
#include <string>
#include <vector>

#include <gtest/gtest.h>
#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/device_id.h"
#include "xchainer/dtype.h"
#include "xchainer/testing/array.h"
#include "xchainer/testing/array_check.h"
#include "xchainer/testing/device_session.h"

namespace xchainer {
namespace {

class LogicTest : public ::testing::TestWithParam<std::string> {
protected:
    void SetUp() override {
        const std::string& backend_name = GetParam();
        device_session_.emplace(DeviceId{backend_name, 0});
    }

    void TearDown() override { device_session_.reset(); }

private:
    nonstd::optional<testing::DeviceSession> device_session_;
};

TEST_P(LogicTest, Equal) {
    using T = float;

    struct Param {
        T a;
        T b;
        bool e;
    };

    std::vector<Param> data = {{1.0f, 1.0f, true},
                               {1.0f, -1.0f, false},
                               {2.0f, 3.0f, false},
                               {1.0f, std::nanf(""), false},
                               {std::nanf(""), std::nanf(""), false},
                               {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), true},
                               {0.0f, -0.0f, true}};
    std::vector<T> a_data;
    std::vector<T> b_data;
    std::vector<bool> e_data;
    std::transform(data.begin(), data.end(), std::back_inserter(a_data), [](const auto& param) { return param.a; });
    std::transform(data.begin(), data.end(), std::back_inserter(b_data), [](const auto& param) { return param.b; });
    std::transform(data.begin(), data.end(), std::back_inserter(e_data), [](const auto& param) { return param.e; });
    Shape shape{static_cast<int64_t>(data.size())};
    Array a = testing::BuildArray(shape).WithData<T>(a_data.begin(), a_data.end());
    Array b = testing::BuildArray(shape).WithData<T>(b_data.begin(), b_data.end());
    Array e = testing::BuildArray(shape).WithData<bool>(e_data.begin(), e_data.end());
    Array c = Equal(a, b);

    ASSERT_EQ(c.dtype(), Dtype::kBool);
    EXPECT_TRUE(c.IsContiguous());
    testing::ExpectEqual<bool>(e, c);
}

TEST_P(LogicTest, EqualBroadcast) {
    using T = int32_t;

    Array a = testing::BuildArray({2, 3}).WithLinearData<T>();
    Array b = testing::BuildArray({2, 1}).WithLinearData<T>();
    Array e = testing::BuildArray({2, 3}).WithData<bool>({true, false, false, false, false, false});
    Array o = Equal(a, b);
    testing::ExpectEqual<bool>(e, o);
}

INSTANTIATE_TEST_CASE_P(
        ForEachBackend,
        LogicTest,
        ::testing::Values(
#ifdef XCHAINER_ENABLE_CUDA
                std::string{"cuda"},
#endif  // XCHAINER_ENABLE_CUDA
                std::string{"native"}));

}  // namespace
}  // namespace xchainer
<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
// setupSender
// - クライアントとの通信系を構築します。
// - Note: 宛先は固定です。

void ofApp::setupSender(bool flag){

    // フラグの初期化
    bSendMode = flag;
    _prevSendTime = ofGetElapsedTimeMillis();

    if (!bSendMode) {
        // 送信オフ
        cout << "setupSender....NO --- No use clients." << endl;
        return;

    } else {
        // 送信オン
        cout << "setupSender...YES" << endl;

        // ofxOSCの初期化
        // 宛先は3つ。
        senders[0].setup("127.0.0.1", 3001); // Tested with Max
//        senders[0].setup("127.0.0.1", 12011);
        senders[1].setup("127.0.0.1", 12022);
        senders[2].setup("127.0.0.1", 12033);
    }
}

//--------------------------------------------------------------
// updateSender
// - クライアントとの通信を更新します。
// - Note: 宛先は固定です。

void ofApp::updateSender(){

    // 送信モードかつ、送信対象メッセージありの時のみ送信
    if (bSendMode && bNeedSending) {

        // 送信タイミングの調整。
        // 所定インターバルを経過していれば送信する。
        if (ofGetElapsedTimeMillis() > _prevSendTime + sendInterval ){

            _prevSendTime = ofGetElapsedTimeMillis();

            cout << "send!" << endl;
            send();

            // 後始末 - 1回ぽっきりで送信を抑止する場合はコメントアウトする。
            // bNeedSending = false;
        }
    }
}

//--------------------------------------------------------------
// send
// - クライアントとの通信をおこないます。
// - Note: 宛先は固定です。
// - TODO: OSCバンドルするべき？

void ofApp::send(){

    // メッセージ送信
    ofxOscMessage m0, m1, m2, m3, m4, m5;
    m0.setAddress("/dsng2/ctl/FRAMEINFO"); // 送信回次 int, 時刻 float
    m1.setAddress("/dsng2/ctl/sp");  // 速さ(スカラー量), float
    m2.setAddress("/dsng2/ctl/st");  // ハンドル角 (-1.0 〜 1.0), float
    m3.setAddress("/dsng2/ctl/dir"); // 方角 0-360, float
    m4.setAddress("/dsng2/ctl/px");  // 位置.x座標 , float
    m5.setAddress("/dsng2/ctl/py");  // 位置.y座標, float

    m0.addIntArg(_sendCount++);
    m0.addFloatArg(ofGetElapsedTimeMillis());
    m1.addFloatArg(bike._speed);
    m2.addFloatArg(bike._steer);
    m3.addFloatArg(bike._direction);
    m4.addFloatArg(bike._location.x);
    m5.addFloatArg(bike._location.y);

    // 各宛先に送信
    for (int i =0; i<3; i++) {
        senders[i].sendMessage(m0);
        senders[i].sendMessage(m1);
        senders[i].sendMessage(m2);
        senders[i].sendMessage(m3);
        senders[i].sendMessage(m4);
        senders[i].sendMessage(m5);
    }
}

<commit_msg>cleaning<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
// setupSender
// - クライアントとの通信系を構築します。
// - Note: 宛先は固定です。

void ofApp::setupSender(bool flag){

    // フラグの初期化
    bSendMode = flag;
    _prevSendTime = ofGetElapsedTimeMillis();

    if (!bSendMode) {
        // 送信オフ
        cout << "setupSender....NO --- No use clients." << endl;
        return;

    } else {
        // 送信オン
        cout << "setupSender...YES" << endl;

        // ofxOSCの初期化
        // 宛先は3つ。
//        senders[0].setup("127.0.0.1", 3001); // Tested with Max
        senders[0].setup("127.0.0.1", 12011);
        senders[1].setup("127.0.0.1", 12022);
        senders[2].setup("127.0.0.1", 12033);
    }
}

//--------------------------------------------------------------
// updateSender
// - クライアントとの通信を更新します。
// - Note: 宛先は固定です。

void ofApp::updateSender(){

    // 送信モードかつ、送信対象メッセージありの時のみ送信
    if (bSendMode && bNeedSending) {

        // 送信タイミングの調整。
        // 所定インターバルを経過していれば送信する。
        if (ofGetElapsedTimeMillis() > _prevSendTime + sendInterval ){

            _prevSendTime = ofGetElapsedTimeMillis();

            cout << "send!" << endl;
            send();

            // 後始末 - 1回ぽっきりで送信を抑止する場合はコメントアウトする。
            // bNeedSending = false;
        }
    }
}

//--------------------------------------------------------------
// send
// - クライアントとの通信をおこないます。
// - Note: 宛先は固定です。
// - TODO: OSCバンドルするべき？

void ofApp::send(){

    // メッセージ作成
    ofxOscMessage m0, m1, m2, m3, m4, m5;
    m0.setAddress("/dsng2/ctl/FRAMEINFO"); // 送信回次 int, 時刻 float
    m1.setAddress("/dsng2/ctl/sp");  // 速さ(スカラー量), float
    m2.setAddress("/dsng2/ctl/st");  // ハンドル角 (-1.0 〜 1.0), float
    m3.setAddress("/dsng2/ctl/dir"); // 方角 0-360, float
    m4.setAddress("/dsng2/ctl/px");  // 位置.x座標 , float
    m5.setAddress("/dsng2/ctl/py");  // 位置.y座標, float

    m0.addIntArg(_sendCount++);
    m0.addFloatArg(ofGetElapsedTimeMillis());
    m1.addFloatArg(bike._speed);
    m2.addFloatArg(bike._steer);
    m3.addFloatArg(bike._direction);
    m4.addFloatArg(bike._location.x);
    m5.addFloatArg(bike._location.y);

    // 各宛先に送信
    for (int i =0; i<3; i++) {
        senders[i].sendMessage(m0);
        senders[i].sendMessage(m1);
        senders[i].sendMessage(m2);
        senders[i].sendMessage(m3);
        senders[i].sendMessage(m4);
        senders[i].sendMessage(m5);
    }
}

<|endoftext|>


<commit_before>/* MIKOEDGEN
 *
 * Mikola Samardak's Edit Script Generator, implemented as a dare,
 * using Myers's algorithm from
 * „An O(ND) Difference Algorithm and Its Variations“.
 *
 * Currently suits better for binary, mostly because output can
 * hardly be considered human-readable.
 * Output script consists of sequence of instructions and raw data
 * to be inserted or deleted.
 * Format:
 *   @a,b: - jump to offsets a, b for first and second string respectively.
 *   +c:A - insert array A of length c.
 *   -c:A - delete array A of length c.
 *
 * TODO: compact together sequences of hunks with the same operation.
 *
 * TODO: it would be cool and more convenient to represent a and b positions
 *       as a 2-dimensional points instead of separate values.
 *
 * TODO: incorporate optimizations described in part 4 of the paper.
 */

#include <algorithm>
#include <cassert>
#include <iostream>
#include <unordered_map>
#include <vector>

enum DiffOp {
	DIFF_INSERT,
	DIFF_DELETE,
	DIFF_NOP,
};

struct Hunk {
	int apos;
	int bpos;
	DiffOp op;
	int length;
};

struct Snake {
	int astart, bstart;
	int amid, bmid;
	int aend, bend;

	bool is_valid() const {
		return     (astart <= amid && bstart <= bmid)
			&& ((aend - amid) == (bend - bmid));
	}

	bool has_diagonal() const {
		return (amid == aend) && (bend == bmid);
	}

	DiffOp diff_op() const {
		if (astart < amid) {
			return DIFF_DELETE;
		} else if (bstart < bmid) {
			return DIFF_INSERT;
		} else {
			return DIFF_NOP;
		}
	}
};

static
std::ostream& operator << (std::ostream& s, const Snake& snake) {
	s << "Snake{";
	s << std::to_string(snake.astart) + ",";
	s << std::to_string(snake.bstart) + ",";
	s << std::to_string(snake.amid) + ",";
	s << std::to_string(snake.bmid) + ",";
	s << std::to_string(snake.aend) + ",";
	s << std::to_string(snake.bend);
	s << "}";
	return s;
}

static
std::vector<Hunk> process_snakes(std::vector<Snake> snakes) {
	std::vector<Hunk> hunks;
	Hunk hunk;
	for (auto snake = snakes.cbegin(); snake != snakes.cend(); snake--) {
		if (snake->bstart == -1) {
			continue;
		}

		DiffOp op = snake->diff_op();
		if (op == DIFF_NOP) {
			continue;
		}

		if (op == hunk.op && !snake->has_diagonal()) {
			hunk.apos = snake->astart;
			hunk.bpos = snake->bstart;
			hunk.length++;
		} else {
			hunks.push_back(hunk);
			hunk = Hunk{
				snake->astart,
				snake->bstart,
				op,
				1,
			};
		}
	}
	std::reverse(hunks.begin(), hunks.end());
	return std::move(hunks);
}

static
std::vector<std::unordered_map<int,int>> compute_trace(std::string a, std::string b) {
	const int alen = a.size();
	const int blen = b.size();

	std::vector<std::unordered_map<int,int>> vs;
	std::unordered_map<int,int> v;
	v[1] = 0;
	for (int d = 0; d <= alen + blen; d++) {
		bool solved = false;
		for (int k = -d; k <= d; k += 2) {
			int apos;
			if (k == -d || (k != d && v[k-1] < v[k+1])) {
				apos = v[k+1];
			} else {
				apos = v[k-1]+1;
			}
			int bpos = apos - k;
			while (apos < alen && bpos < blen && a[apos] == b[bpos]) {
				apos++;
				bpos++;
			}
			v[k] = apos;
			if (apos >= alen && bpos >= blen) {
				solved = true;
				break;
			}
		}
		vs.push_back(std::unordered_map<int,int>(v));

		if (solved) {
			return std::move(vs);
		}
	}

	throw std::logic_error("Unable to solve trace. Should actually never happen >vv<");
}

static
std::vector<Hunk> compute_hunks(std::string a, std::string b) {
	const int alen = a.size();
	const int blen = b.size();

	std::vector<std::unordered_map<int,int>> vs;

	// find shortest D-path
	std::unordered_map<int,int> v;
	v[1] = 0;
	for (int d = 0; d <= alen + blen; d++) {
		bool solved = false;
		std::cout << "d: " << d << "\n";
		for (int k = -d; k <= d; k += 2) {
			int apos;
			int bpos;
			if (k == -d || (k != d && v[k-1] < v[k+1])) {
				apos = v[k+1];
			} else {
				apos = v[k-1]+1;
			}
			bpos = apos - k;
			while (apos < alen && bpos < blen && a[apos] == b[bpos]) {
				apos++;
				bpos++;
			}
			v[k] = apos;
			std::cout << "v[" << k << "] = (" << apos << "," << bpos << ")\n";
			if (apos >= alen && bpos >= blen) {
				std::cout << "found solution of length " << d << "\n";
				solved = true;
				break;
			}
		}
		vs.push_back(std::unordered_map<int,int>(v));

		if (solved) {
			break;
		}
	}

	// calculate snakes starting at the last endpoint
	std::vector<Snake> snakes;
	int apos = alen;
	int bpos = blen;
	for (int d = vs.size() - 1; apos > 0 || bpos > 0; d--) {
		auto v = vs[d];

		std::cout << "d: " << d << "\n";
		std::cout << "pos: (" << apos << "," << bpos << ")\n";

		int k = apos - bpos;

		// end
		int aend = v[k];
		int bend = apos - k;

		bool down = (k == -d || (k != d && v[k-1] < v[k+1]));
		int kprev = (down) ? k+1 : k-1;

		// start
		int astart = v[kprev];
		int bstart = astart - kprev;

		// middle
		int amid = (down) ? astart : astart + 1;
		int bmid = amid - k;

		Snake snake{astart, bstart, amid, bmid, aend, bend};
		snakes.push_back(snake);

		apos = astart;
		bpos = bstart;
	}

	return process_snakes(snakes);
}

int main(void) {
	std::string a = "CABCABBA";
	std::string b = "CBABACA";
	auto snakes = compute_snakes(a, b);
	std::cout << "\nSnakes:\n";
	for (auto snake = snakes.begin(); snake != snakes.end(); ++snake) {
		std::cout << *snake << "\n";
	}
}

// vim: tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab
<commit_msg>main: implement generating diff output.<commit_after>/* MIKOEDGEN
 *
 * Mikola Samardak's Edit Script Generator, implemented as a dare,
 * using Myers's algorithm from
 * „An O(ND) Difference Algorithm and Its Variations“.
 *
 * Currently suits better for binary, mostly because output can
 * hardly be considered human-readable.
 * Output script consists of sequence of instructions and raw data
 * to be inserted or deleted.
 * Format:
 *   @a,b: - jump to offsets a, b for first and second string respectively.
 *   +c:A - insert array A of length c.
 *   -c:A - delete array A of length c.
 *
 * TODO: compact together sequences of hunks with the same operation.
 *
 * TODO: it would be cool and more convenient to represent a and b positions
 *       as a 2-dimensional points instead of separate values.
 *
 * TODO: incorporate optimizations described in part 4 of the paper.
 */

#include <algorithm>
#include <cassert>
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <vector>

enum DiffOp {
	DIFF_INSERT,
	DIFF_DELETE,
	DIFF_NOP,
};

struct Snake {
	int astart, bstart;
	int amid, bmid;
	int aend, bend;

	bool is_valid() const {
		return	(astart <= amid && bstart <= bmid)
			&& ((aend - amid) == (bend - bmid));
	}

	bool has_diagonal() const {
		return (amid == aend) && (bend == bmid);
	}

	DiffOp diff_op() const {
		if (astart < amid) {
			return DIFF_DELETE;
		} else if (bstart < bmid) {
			return DIFF_INSERT;
		} else {
			return DIFF_NOP;
		}
	}
};

struct Hunk {
	int apos;
	int bpos;
	DiffOp op;
	int length;
	std::string data;

	std::string marshall() const {
		std::string s;
		s += "@" + std::to_string(apos) + "," + std::to_string(bpos) + ":";

		if (op == DIFF_INSERT) {
			s += "+";
		} else if (op == DIFF_DELETE) {
			s += "-";
		} else {
			throw std::logic_error("Bad DiffOp");
		}

		s += std::to_string(length);
		s += ":";
		s += data;

		return std::move(s);
	}
};

static
std::vector<std::unordered_map<int,int>> compute_trace(std::string a, std::string b) {
	const int alen = a.size();
	const int blen = b.size();

	std::vector<std::unordered_map<int,int>> vs;
	std::unordered_map<int,int> v;
	v[1] = 0;
	for (int d = 0; d <= alen + blen; d++) {
		bool solved = false;
		for (int k = -d; k <= d; k += 2) {
			int apos;
			if (k == -d || (k != d && v[k-1] < v[k+1])) {
				apos = v[k+1];
			} else {
				apos = v[k-1]+1;
			}
			int bpos = apos - k;
			while (apos < alen && bpos < blen && a[apos] == b[bpos]) {
				apos++;
				bpos++;
			}
			v[k] = apos;
			if (apos >= alen && bpos >= blen) {
				solved = true;
				break;
			}
		}
		vs.push_back(std::unordered_map<int,int>(v));

		if (solved) {
			return std::move(vs);
		}
	}

	throw std::logic_error("Unable to solve trace. Should actually never happen >vv<");
}

static
std::vector<Snake> compute_snakes(
		const std::vector<std::unordered_map<int,int>> vs,
		const int alen, const int blen
) {
	std::vector<Snake> snakes;
	int apos = alen;
	int bpos = blen;
	for (int d = vs.size() - 1; apos > 0 || bpos > 0; d--) {
		auto v = vs[d];

		int k = apos - bpos;

		// end
		int aend = v[k];
		int bend = apos - k;

		bool down = (k == -d || (k != d && v[k-1] < v[k+1]));
		int kprev = (down) ? k+1 : k-1;

		// start
		int astart = v[kprev];
		int bstart = astart - kprev;

		// middle
		int amid = (down) ? astart : astart + 1;
		int bmid = amid - k;

		Snake snake{astart, bstart, amid, bmid, aend, bend};
		snakes.push_back(snake);

		apos = astart;
		bpos = bstart;
	}
	return std::move(snakes);
}

static
std::vector<Hunk> process_snakes(std::vector<Snake> snakes) {
	std::vector<Hunk> hunks;
	Hunk hunk = {};
	for (auto snake = snakes.cbegin(); snake != snakes.cend(); snake++) {
		if (snake->bstart == -1) {
			continue;
		}

		DiffOp op = snake->diff_op();
		if (op == DIFF_NOP) {
			continue;
		}

		// TODO: merge sequences of hunks with the same op.
		hunk = Hunk {
			snake->astart,
			snake->bstart,
			op,
			1,
		};
		hunks.push_back(hunk);
	}
	std::reverse(hunks.begin(), hunks.end());
	return std::move(hunks);
}

static
std::vector<Hunk> compute_hunks(std::string a, std::string b) {
	const int alen = a.size();
	const int blen = b.size();

	std::vector<std::unordered_map<int,int>> vs = compute_trace(a, b);

	std::vector<Snake> snakes = compute_snakes(vs, alen, blen);

	std::vector<Hunk> hunks = process_snakes(snakes);

	// а потім маленьке звірятко загортає все це у фольгу
	for (auto hunk = hunks.begin(); hunk != hunks.end(); hunk++) {
		if (hunk->op == DIFF_INSERT) {
			hunk->data = b.substr(hunk->bpos, hunk->length);
		} else {
			hunk->data = a.substr(hunk->apos, hunk->length);
		}
	}

	return std::move(hunks);
}

int main(int argc, char* argv[]) {
	if (argc != 3) {
		std::cout << "Usage:\n";
		std::cout << "  " << argv[0] << " <file1> <file2>";
		return -1;
	}

	std::ifstream file1;
	file1.exceptions(std::ifstream::failbit);
	file1.open(argv[1], std::ifstream::in | std::ifstream::binary);
	std::ifstream file2;
	file2.exceptions(std::ifstream::failbit);
	file2.open(argv[2], std::ifstream::in | std::ifstream::binary);

	std::string a(
			(std::istreambuf_iterator<char>(file1)),
			(std::istreambuf_iterator<char>())
	);
	std::string b(
			(std::istreambuf_iterator<char>(file2)),
			(std::istreambuf_iterator<char>())
	);

	std::cout << "-" << a;
	std::cout << "+" << b;

	auto hunks = compute_hunks(a, b);
	std::cout << "\nHunks:\n";
	for (auto hunk = hunks.cbegin(); hunk != hunks.cend(); ++hunk) {
		std::cout << hunk->marshall() << "\n";
	}
}

// vim: tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab
<|endoftext|>


<commit_before>#include "command_file.hpp"

#include "list.hpp"
#include "object_schema.hpp"
#include "property.hpp"
#include "results.hpp"
#include "schema.hpp"
#include "impl/realm_coordinator.hpp"

#include <realm/commit_log.hpp>
#include <realm/disable_sync_to_disk.hpp>
#include <realm/group_shared.hpp>
#include <realm/link_view.hpp>

#include <iostream>
#include <sstream>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

using namespace realm;

#define FUZZ_SORTED 0
#define FUZZ_LINKVIEW 1
#define FUZZ_LOG 0

// Read from a fd until eof into a string
// Needs to use unbuffered i/o to work properly with afl
static void read_all(std::string& buffer, int fd)
{
    buffer.clear();
    size_t offset = 0;
    while (true) {
        buffer.resize(offset + 4096);
        ssize_t bytes_read = read(fd, &buffer[offset], 4096);
        if (bytes_read < 4096) {
            buffer.resize(offset + bytes_read);
            break;
        }
        offset += 4096;
    }
}

static Query query(fuzzer::RealmState& state)
{
#if FUZZ_LINKVIEW
    return state.table.where(state.lv);
#else
    return state.table.where().greater(1, 100).less(1, 50000);
#endif
}

static TableView tableview(fuzzer::RealmState& state)
{
    auto tv = query(state).find_all();
#if FUZZ_SORTED
    tv.sort({1, 0}, {true, true});
#endif
    return tv;
}

// Apply the changes from the command file and then return whether a change
// notification should occur
static bool apply_changes(fuzzer::CommandFile& commands, fuzzer::RealmState& state)
{
    auto tv = tableview(state);
#if FUZZ_LOG
    for (size_t i = 0; i < tv.size(); ++i)
        fprintf(stderr, "pre: %lld\n", tv.get_int(0, i));
#endif

    commands.run(state);

    auto tv2 = tableview(state);
    if (tv.size() != tv2.size())
        return true;

    for (size_t i = 0; i < tv.size(); ++i) {
#if FUZZ_LOG
        fprintf(stderr, "%lld %lld\n", tv.get_int(0, i), tv2.get_int(0, i));
#endif
        if (!tv.is_row_attached(i))
            return true;
        if (tv.get_int(0, i) != tv2.get_int(0, i))
            return true;
        if (find(begin(state.modified), end(state.modified), tv.get_int(0, i)) != end(state.modified))
            return true;
    }

    return false;
}

static void verify(CollectionChangeIndices const& changes, std::vector<int64_t> values, fuzzer::RealmState& state)
{
    auto tv = tableview(state);

    // Apply the changes from the transaction log to our copy of the
    // initial, using UITableView's batching rules (i.e. delete, then
    // insert, then update)
    auto it = util::make_reverse_iterator(changes.deletions.end());
    auto end = util::make_reverse_iterator(changes.deletions.begin());
    for (; it != end; ++it) {
        values.erase(values.begin() + it->first, values.begin() + it->second);
    }

    for (auto i : changes.insertions.as_indexes()) {
        values.insert(values.begin() + i, tv.get_int(1, i));
    }

    if (values.size() != tv.size()) {
        abort();
    }

    for (auto i : changes.modifications.as_indexes()) {
        if (changes.insertions.contains(i))
            abort();
        values[i] = tv.get_int(1, i);
    }

#if FUZZ_SORTED
    if (!std::is_sorted(values.begin(), values.end()))
        abort();
#endif

    for (size_t i = 0; i < values.size(); ++i) {
        if (values[i] != tv.get_int(1, i)) {
#if FUZZ_LOG
            fprintf(stderr, "%lld %lld\n", values[i], tv.get_int(1, i));
#endif
            abort();
        }
    }
}

static void test(Realm::Config const& config, SharedRealm& r, SharedRealm& r2, std::istream& input_stream)
{
    fuzzer::RealmState state = {
        *r,
        *_impl::RealmCoordinator::get_existing_coordinator(r->config().path),
        *r->read_group()->get_table("class_object"),
        r->read_group()->get_table("class_linklist")->get_linklist(0, 0),
        0,
        {}
    };

    fuzzer::CommandFile command(input_stream);
    if (command.initial_values.empty()) {
        return;
    }
    command.import(state);

    fuzzer::RealmState state2 = {
        *r2,
        state.coordinator,
        *r2->read_group()->get_table("class_object"),
        r2->read_group()->get_table("class_linklist")->get_linklist(0, 0),
        state.uid,
        {}
    };

#if FUZZ_LINKVIEW && !FUZZ_SORTED
    auto results = List(r, ObjectSchema(), state.lv);
#else
    auto results = Results(r, ObjectSchema(), query(state))
#if FUZZ_SORTED
        .sort({{1, 0}, {true, true}})
#endif
        ;
#endif // FUZZ_LINKVIEW

    std::vector<int64_t> initial_values;
    for (size_t i = 0; i < results.size(); ++i)
        initial_values.push_back(results.get(i).get_int(1));

    CollectionChangeIndices changes;
    int notification_calls = 0;
    auto token = results.add_notification_callback([&](CollectionChangeIndices c, std::exception_ptr err) {
        if (notification_calls > 0 && c.empty())
            abort();
        changes = c;
        ++notification_calls;
    });

    state.coordinator.on_change(); r->notify();
    if (notification_calls != 1) {
        abort();
    }

    bool expect_notification = apply_changes(command, state2);
    state.coordinator.on_change(); r->notify();

    if (notification_calls != 1 + expect_notification) {
        abort();
    }

    verify(changes, initial_values, state);
}

int main(int argc, char** argv) {
    std::ios_base::sync_with_stdio(false);
    realm::disable_sync_to_disk();

    Realm::Config config;
    config.path = "fuzzer.realm";
    config.cache = false;
    config.in_memory = true;
    config.automatic_change_notifications = false;

    Schema schema{
        {"object", "", {
            {"id", PropertyTypeInt},
            {"value", PropertyTypeInt}
        }},
        {"linklist", "", {
            {"list", PropertyTypeArray, "object"}
        }}
    };

    config.schema = std::make_unique<Schema>(schema);
    unlink(config.path.c_str());

    auto r = Realm::get_shared_realm(config);
    auto r2 = Realm::get_shared_realm(config);
    auto& coordinator = *_impl::RealmCoordinator::get_existing_coordinator(config.path);

    r->begin_transaction();
    r->read_group()->get_table("class_linklist")->add_empty_row();
    r->commit_transaction();

    auto test_on = [&](auto& buffer) {
        std::istringstream ss(buffer);
        test(config, r, r2, ss);
        if (r->is_in_transaction())
            r->cancel_transaction();
        r2->invalidate();
        coordinator.on_change();
    };

    if (argc > 1) {
        std::string buffer;
        for (int i = 1; i < argc; ++i) {
            int fd = open(argv[i], O_RDONLY);
            if (fd < 0)
                abort();
            read_all(buffer, fd);
            close(fd);

            test_on(buffer);
        }
        unlink(config.path.c_str());
        return 0;
    }

#ifdef __AFL_HAVE_MANUAL_CONTROL
    std::string buffer;
    while (__AFL_LOOP(1000)) {
        read_all(buffer, 0);
        test_on(buffer);
    }
#else
    std::string buffer;
    read_all(buffer, 0);
    test_on(buffer);
#endif

    unlink(config.path.c_str());
    return 0;
}
<commit_msg>Allow non-empty no-op changesets when there should be no notification in the fuzzer<commit_after>#include "command_file.hpp"

#include "list.hpp"
#include "object_schema.hpp"
#include "property.hpp"
#include "results.hpp"
#include "schema.hpp"
#include "impl/realm_coordinator.hpp"

#include <realm/commit_log.hpp>
#include <realm/disable_sync_to_disk.hpp>
#include <realm/group_shared.hpp>
#include <realm/link_view.hpp>

#include <iostream>
#include <sstream>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

using namespace realm;

#define FUZZ_SORTED 0
#define FUZZ_LINKVIEW 1
#define FUZZ_LOG 0

// Read from a fd until eof into a string
// Needs to use unbuffered i/o to work properly with afl
static void read_all(std::string& buffer, int fd)
{
    buffer.clear();
    size_t offset = 0;
    while (true) {
        buffer.resize(offset + 4096);
        ssize_t bytes_read = read(fd, &buffer[offset], 4096);
        if (bytes_read < 4096) {
            buffer.resize(offset + bytes_read);
            break;
        }
        offset += 4096;
    }
}

static Query query(fuzzer::RealmState& state)
{
#if FUZZ_LINKVIEW
    return state.table.where(state.lv);
#else
    return state.table.where().greater(1, 100).less(1, 50000);
#endif
}

static TableView tableview(fuzzer::RealmState& state)
{
    auto tv = query(state).find_all();
#if FUZZ_SORTED
    tv.sort({1, 0}, {true, true});
#endif
    return tv;
}

// Apply the changes from the command file and then return whether a change
// notification should occur
static bool apply_changes(fuzzer::CommandFile& commands, fuzzer::RealmState& state)
{
    auto tv = tableview(state);
#if FUZZ_LOG
    for (size_t i = 0; i < tv.size(); ++i)
        fprintf(stderr, "pre: %lld\n", tv.get_int(0, i));
#endif

    commands.run(state);

    auto tv2 = tableview(state);
    if (tv.size() != tv2.size())
        return true;

    for (size_t i = 0; i < tv.size(); ++i) {
#if FUZZ_LOG
        fprintf(stderr, "%lld %lld\n", tv.get_int(0, i), tv2.get_int(0, i));
#endif
        if (!tv.is_row_attached(i))
            return true;
        if (tv.get_int(0, i) != tv2.get_int(0, i))
            return true;
        if (find(begin(state.modified), end(state.modified), tv.get_int(0, i)) != end(state.modified))
            return true;
    }

    return false;
}

static auto verify(CollectionChangeIndices const& changes, std::vector<int64_t> values, fuzzer::RealmState& state)
{
    auto tv = tableview(state);

    // Apply the changes from the transaction log to our copy of the
    // initial, using UITableView's batching rules (i.e. delete, then
    // insert, then update)
    auto it = util::make_reverse_iterator(changes.deletions.end());
    auto end = util::make_reverse_iterator(changes.deletions.begin());
    for (; it != end; ++it) {
        values.erase(values.begin() + it->first, values.begin() + it->second);
    }

    for (auto i : changes.insertions.as_indexes()) {
        values.insert(values.begin() + i, tv.get_int(1, i));
    }

    if (values.size() != tv.size()) {
        abort();
    }

    for (auto i : changes.modifications.as_indexes()) {
        if (changes.insertions.contains(i))
            abort();
        values[i] = tv.get_int(1, i);
    }

#if FUZZ_SORTED
    if (!std::is_sorted(values.begin(), values.end()))
        abort();
#endif

    for (size_t i = 0; i < values.size(); ++i) {
        if (values[i] != tv.get_int(1, i)) {
#if FUZZ_LOG
            fprintf(stderr, "%lld %lld\n", values[i], tv.get_int(1, i));
#endif
            abort();
        }
    }

    return values;
}

static void verify_no_op(CollectionChangeIndices const& changes, std::vector<int64_t> values, fuzzer::RealmState& state)
{
    auto new_values = verify(changes, values, state);
    if (!std::equal(begin(values), end(values), begin(new_values), end(new_values)))
        abort();
}

static void test(Realm::Config const& config, SharedRealm& r, SharedRealm& r2, std::istream& input_stream)
{
    fuzzer::RealmState state = {
        *r,
        *_impl::RealmCoordinator::get_existing_coordinator(r->config().path),
        *r->read_group()->get_table("class_object"),
        r->read_group()->get_table("class_linklist")->get_linklist(0, 0),
        0,
        {}
    };

    fuzzer::CommandFile command(input_stream);
    if (command.initial_values.empty()) {
        return;
    }
    command.import(state);

    fuzzer::RealmState state2 = {
        *r2,
        state.coordinator,
        *r2->read_group()->get_table("class_object"),
        r2->read_group()->get_table("class_linklist")->get_linklist(0, 0),
        state.uid,
        {}
    };

#if FUZZ_LINKVIEW && !FUZZ_SORTED
    auto results = List(r, ObjectSchema(), state.lv);
#else
    auto results = Results(r, ObjectSchema(), query(state))
#if FUZZ_SORTED
        .sort({{1, 0}, {true, true}})
#endif
        ;
#endif // FUZZ_LINKVIEW

    std::vector<int64_t> initial_values;
    for (size_t i = 0; i < results.size(); ++i)
        initial_values.push_back(results.get(i).get_int(1));

    CollectionChangeIndices changes;
    int notification_calls = 0;
    auto token = results.add_notification_callback([&](CollectionChangeIndices c, std::exception_ptr err) {
        if (notification_calls > 0 && c.empty())
            abort();
        changes = c;
        ++notification_calls;
    });

    state.coordinator.on_change(); r->notify();
    if (notification_calls != 1) {
        abort();
    }

    bool expect_notification = apply_changes(command, state2);
    state.coordinator.on_change(); r->notify();

    if (expect_notification) {
        if (notification_calls != 2)
            abort();
        verify(changes, initial_values, state);
    }
    else {
        if (notification_calls == 2)
            verify_no_op(changes, initial_values, state);
    }
}

int main(int argc, char** argv) {
    std::ios_base::sync_with_stdio(false);
    realm::disable_sync_to_disk();

    Realm::Config config;
    config.path = "fuzzer.realm";
    config.cache = false;
    config.in_memory = true;
    config.automatic_change_notifications = false;

    Schema schema{
        {"object", "", {
            {"id", PropertyTypeInt},
            {"value", PropertyTypeInt}
        }},
        {"linklist", "", {
            {"list", PropertyTypeArray, "object"}
        }}
    };

    config.schema = std::make_unique<Schema>(schema);
    unlink(config.path.c_str());

    auto r = Realm::get_shared_realm(config);
    auto r2 = Realm::get_shared_realm(config);
    auto& coordinator = *_impl::RealmCoordinator::get_existing_coordinator(config.path);

    r->begin_transaction();
    r->read_group()->get_table("class_linklist")->add_empty_row();
    r->commit_transaction();

    auto test_on = [&](auto& buffer) {
        std::istringstream ss(buffer);
        test(config, r, r2, ss);
        if (r->is_in_transaction())
            r->cancel_transaction();
        r2->invalidate();
        coordinator.on_change();
    };

    if (argc > 1) {
        std::string buffer;
        for (int i = 1; i < argc; ++i) {
            int fd = open(argv[i], O_RDONLY);
            if (fd < 0)
                abort();
            read_all(buffer, fd);
            close(fd);

            test_on(buffer);
        }
        unlink(config.path.c_str());
        return 0;
    }

#ifdef __AFL_HAVE_MANUAL_CONTROL
    std::string buffer;
    while (__AFL_LOOP(1000)) {
        read_all(buffer, 0);
        test_on(buffer);
    }
#else
    std::string buffer;
    read_all(buffer, 0);
    test_on(buffer);
#endif

    unlink(config.path.c_str());
    return 0;
}
<|endoftext|>


<commit_before>#include "gamemechanics.h"
#include <QPainter>
#include <QtCore/qmath.h>
#include <QLabel>
#include <QMouseEvent>

GameMechanics::GameMechanics(QWidget *parent) :
        QWidget(parent)
{
    imageName = new QString();
    pieceCount = 3;
    array = new Piece*[pieceCount];
    for (int i = 0; i < pieceCount; i++)
        array[i] = new Piece[pieceCount];

    for (int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
        {
            array[x][y].x = x;
            array[x][y].y = y;
        }
    typeOfPainting = empty;
    winflag = false;
}

//-----------------------------------------

void GameMechanics::mixArray()
    //Начинаем перемешивать части картинок по алгоритму
{
    int mas[2] = {-1,1};
    int x, y;
    for(int i = 0; i<23 * pieceCount; i++)
    {
        x = abs((mas[rand() % 2] + emptyImagePos.x()) % pieceCount);
        y = abs((mas[rand() % 2] + emptyImagePos.x()) % pieceCount);
        if (!swapEmpty(x, emptyImagePos.y()))
            i--;
        if (!swapEmpty(emptyImagePos.x(), y))
            i--;
    }
}

//-----------------------------------------

void GameMechanics::newGame()
{
    pieceWidth = this->width() / pieceCount;
    pieceHeight = this->height() / pieceCount;
    typeOfPainting = fullImage;
    QImage temp(*imageName);
    temp = temp.scaled(QSize(this->width() + pieceCount, this->height()));
    image = &temp;
    for (int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
        {
            array[x][y].x = x;
            array[x][y].y = y;
        }
    for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                array[x][y].img = image->copy(pieceWidth * x, pieceHeight * y, pieceWidth, pieceHeight);
    emptyImagePos.setX(pieceCount - 1);
    emptyImagePos.setY(pieceCount - 1);
    winflag = false;
    repaint();
    mixArray();
    typeOfPainting = fullImage;
}

//----------------------------------------

void GameMechanics::hint()
{
    typeOfPainting = fullImage;
    repaint();
}

//----------------------------------------

GameMechanics::~GameMechanics()
{
        for (int i = 0; i < pieceCount; i++)
                delete[] array[i];
        delete[] array;
}

//----------------------------------------

void GameMechanics::paintEvent(QPaintEvent *paintEvent)
{
    QPainter painter(this);
    painter.begin(this);
    int n = 0;
    switch(typeOfPainting)
    {
    case pieces:
        pieceWidth = this->width() / pieceCount;
        pieceHeight = this->height() / pieceCount;
        //рисуем картинки
        for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                    painter.drawImage(pieceWidth * x,pieceHeight * y + y, array[x][y].img);
        painter.setPen(QColor(0, 0, 0));
        painter.setBrush(QColor(255, 255, 255));
        painter.drawRect(pieceWidth * emptyImagePos.x(), pieceHeight * emptyImagePos.y() + emptyImagePos.y(), pieceWidth, pieceHeight);
        //рисуем линии между картинками

        for(int x = pieceWidth; x < this->width(); x += pieceWidth)
            painter.drawLine(x, 0, x, this->height());
        for(int y = pieceHeight; y < this->height(); y += pieceHeight, n++)
            painter.drawLine(0, y + n, this->width(), y+n);
        break;

    case fullImage:
        for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                painter.drawImage(pieceWidth * array[x][y].x, pieceHeight * array[x][y].y, array[x][y].img);
        break;

    default:
        painter.drawText(this->width() / 2 - 70, this->height() / 2 - 15, tr("Begin the game, please!"));
        break;
    };
    painter.end();
}

//----------------------------------------

void GameMechanics::mousePressEvent(QMouseEvent *event)
{
    imagePressed(event->localPos());
}

//----------------------------------------

void GameMechanics::imagePressed(QPointF pos)
{
    if(typeOfPainting == pieces)
    {
        int x = (int)pos.x();
        int y = (int)pos.y();
        x /= pieceWidth;
        y /= pieceHeight;
        if ( x == emptyImagePos.x() && y == emptyImagePos.y())
            return;
        swapEmpty(x,y);
        repaint();
        if(!winflag && checkArray())
        {
            win();
            typeOfPainting = fullImage;
        }

    }
    if(typeOfPainting == fullImage && !winflag)
    {
        typeOfPainting = pieces;
        repaint();
    }
    if(typeOfPainting == fullImage && winflag)
    {
        repaint();
    }
}

//----------------------------------------

int GameMechanics::swapEmpty(int x, int y)
{
    if( (abs(x - emptyImagePos.x()) == 1 && y == emptyImagePos.y()) || (abs(y - emptyImagePos.y()) == 1 && x == emptyImagePos.x()) )
    {
        Piece tempPiece = array[x][y];
        array[x][y] = array[emptyImagePos.x()][emptyImagePos.y()];
        array[emptyImagePos.x()][emptyImagePos.y()] = tempPiece;
        emptyImagePos.setX(x);
        emptyImagePos.setY(y);
        return 1;
    }
    else return 0;
}

//----------------------------------------

bool GameMechanics::checkArray()
{
    for(int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
            if(array[x][y].x != x || array[x][y].y != y) return 0;
    winflag = true;
    return 1;
}

//----------------------------------------

void GameMechanics::changeLevel(int level)
{
    if (level > 1 && level <6)
    {
        for (int i = 0; i < pieceCount; i++)
                delete[] array[i];
        delete[] array;
        pieceCount = level;
        array = new Piece*[pieceCount];
            for (int i = 0; i < pieceCount; i++)
            array[i] = new Piece[pieceCount];

        for (int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
            {
                array[x][y].x = x;
                array[x][y].y = y;
            }
    }
}

//----------------------------------------
<commit_msg>The last commit!!!<commit_after>#include "gamemechanics.h"
#include <QPainter>
#include <QtCore/qmath.h>
#include <QLabel>
#include <QMouseEvent>

GameMechanics::GameMechanics(QWidget *parent) :
        QWidget(parent)
{
    imageName = new QString();
    pieceCount = 2;
    array = new Piece*[pieceCount];
    for (int i = 0; i < pieceCount; i++)
        array[i] = new Piece[pieceCount];

    for (int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
        {
            array[x][y].x = x;
            array[x][y].y = y;
        }
    typeOfPainting = empty;
    winflag = false;
}

//-----------------------------------------

void GameMechanics::mixArray()
    //Начинаем перемешивать части картинок по алгоритму
{
    int mas[2] = {-1,1};
    int x, y;
    for(int i = 0; i<23 * pieceCount; i++)
    {
        x = abs((mas[rand() % 2] + emptyImagePos.x()) % pieceCount);
        y = abs((mas[rand() % 2] + emptyImagePos.x()) % pieceCount);
        if (!swapEmpty(x, emptyImagePos.y()))
            i--;
        if (!swapEmpty(emptyImagePos.x(), y))
            i--;
    }
}

//-----------------------------------------

void GameMechanics::newGame()
{
    pieceWidth = this->width() / pieceCount;
    pieceHeight = this->height() / pieceCount;
    typeOfPainting = fullImage;
    QImage temp(*imageName);
    temp = temp.scaled(QSize(this->width() + pieceCount, this->height()));
    image = &temp;
    for (int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
        {
            array[x][y].x = x;
            array[x][y].y = y;
        }
    for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                array[x][y].img = image->copy(pieceWidth * x, pieceHeight * y, pieceWidth, pieceHeight);
    emptyImagePos.setX(pieceCount - 1);
    emptyImagePos.setY(pieceCount - 1);
    winflag = false;
    repaint();
    mixArray();
    typeOfPainting = fullImage;
}

//----------------------------------------

void GameMechanics::hint()
{
    typeOfPainting = fullImage;
    repaint();
}

//----------------------------------------

GameMechanics::~GameMechanics()
{
        for (int i = 0; i < pieceCount; i++)
                delete[] array[i];
        delete[] array;
}

//----------------------------------------

void GameMechanics::paintEvent(QPaintEvent *paintEvent)
{
    QPainter painter(this);
    painter.begin(this);
    int n = 0;
    switch(typeOfPainting)
    {
    case pieces:
        pieceWidth = this->width() / pieceCount;
        pieceHeight = this->height() / pieceCount;
        //рисуем картинки
        for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                    painter.drawImage(pieceWidth * x,pieceHeight * y + y, array[x][y].img);
        painter.setPen(QColor(0, 0, 0));
        painter.setBrush(QColor(255, 255, 255));
        painter.drawRect(pieceWidth * emptyImagePos.x(), pieceHeight * emptyImagePos.y() + emptyImagePos.y(), pieceWidth, pieceHeight);
        //рисуем линии между картинками

        for(int x = pieceWidth; x < this->width(); x += pieceWidth)
            painter.drawLine(x, 0, x, this->height());
        for(int y = pieceHeight; y < this->height(); y += pieceHeight, n++)
            painter.drawLine(0, y + n, this->width(), y+n);
        break;

    case fullImage:
        for(int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
                painter.drawImage(pieceWidth * array[x][y].x, pieceHeight * array[x][y].y, array[x][y].img);
        break;

    default:
        painter.drawText(this->width() / 2 - 70, this->height() / 2 - 15, tr("Begin the game, please!"));
        break;
    };
    painter.end();
}

//----------------------------------------

void GameMechanics::mousePressEvent(QMouseEvent *event)
{
    imagePressed(event->posF());
}

//----------------------------------------

void GameMechanics::imagePressed(QPointF pos)
{
    if(typeOfPainting == pieces)
    {
        int x = (int)pos.x();
        int y = (int)pos.y();
        x /= pieceWidth;
        y /= pieceHeight;
        if ( x == emptyImagePos.x() && y == emptyImagePos.y())
            return;
        swapEmpty(x,y);
        repaint();
        if(!winflag && checkArray())
        {
            win();
            typeOfPainting = fullImage;
        }

    }
    if(typeOfPainting == fullImage && !winflag)
    {
        typeOfPainting = pieces;
        repaint();
    }
    if(typeOfPainting == fullImage && winflag)
    {
        repaint();
    }
}

//----------------------------------------

int GameMechanics::swapEmpty(int x, int y)
{
    if( (abs(x - emptyImagePos.x()) == 1 && y == emptyImagePos.y()) || (abs(y - emptyImagePos.y()) == 1 && x == emptyImagePos.x()) )
    {
        Piece tempPiece = array[x][y];
        array[x][y] = array[emptyImagePos.x()][emptyImagePos.y()];
        array[emptyImagePos.x()][emptyImagePos.y()] = tempPiece;
        emptyImagePos.setX(x);
        emptyImagePos.setY(y);
        return 1;
    }
    else return 0;
}

//----------------------------------------

bool GameMechanics::checkArray()
{
    for(int x = 0; x < pieceCount; x++)
        for(int y = 0; y < pieceCount; y++)
            if(array[x][y].x != x || array[x][y].y != y) return 0;
    winflag = true;
    return 1;
}

//----------------------------------------

void GameMechanics::changeLevel(int level)
{
    if (level > 1 && level <6)
    {
        for (int i = 0; i < pieceCount; i++)
                delete[] array[i];
        delete[] array;
        pieceCount = level;
        array = new Piece*[pieceCount];
            for (int i = 0; i < pieceCount; i++)
            array[i] = new Piece[pieceCount];

        for (int x = 0; x < pieceCount; x++)
            for(int y = 0; y < pieceCount; y++)
            {
                array[x][y].x = x;
                array[x][y].y = y;
            }
    }
}

//----------------------------------------
<|endoftext|>


<commit_before>//g++ genmasterpair.cpp -lcrypto++ -o genmasterpair

#include <string>
using namespace std;
#include <crypto++/rsa.h>
#include <crypto++/osrng.h>
#include <crypto++/base64.h>
#include <crypto++/files.h>
#include <crypto++/aes.h>
#include <crypto++/modes.h>
#include <crypto++/ripemd.h>
using namespace CryptoPP;

void GenKeyPair()
{
	cout << "Enter master key password" << endl;
	string pass;
	cin >> pass;

	// InvertibleRSAFunction is used directly only because the private key
	// won't actually be used to perform any cryptographic operation;
	// otherwise, an appropriate typedef'ed type from rsa.h would have been used.
	AutoSeededRandomPool rng;
	InvertibleRSAFunction privkey;
	privkey.Initialize(rng, 1024*8);

	// With the current version of Crypto++, MessageEnd() needs to be called
	// explicitly because Base64Encoder doesn't flush its buffer on destruction.
	string privKeyDer;
	StringSink privKeyDerSink(privKeyDer);
	privkey.DEREncode(privKeyDerSink);

	//Hash the pass phrase to create 128 bit key
	string hashedPass;
	RIPEMD128 hash;
	StringSource(pass, true, new HashFilter(hash, new StringSink(hashedPass)));

	// Generate a random IV
	byte iv[AES::BLOCKSIZE];
	rng.GenerateBlock(iv, AES::BLOCKSIZE);

	//Encrypt private key
	CFB_Mode<AES>::Encryption cfbEncryption((const unsigned char*)hashedPass.c_str(), hashedPass.length(), iv);
	byte encPrivKey[privKeyDer.length()+1];
	cfbEncryption.ProcessData(encPrivKey, (const byte*)privKeyDer.c_str(), privKeyDer.length());
	string encPrivKeyStr((char *)encPrivKey, privKeyDer.length());

	//Save private key to file
	StringSource encPrivKeySrc(encPrivKeyStr, true);
	Base64Encoder sink(new FileSink("master-privkey-enc.txt"));
	encPrivKeySrc.CopyTo(sink);
	sink.MessageEnd();

	//Save initialization vector key to file
	StringSource ivStr(iv, AES::BLOCKSIZE, true);
	Base64Encoder sink2(new FileSink("master-privkey-iv.txt"));
	ivStr.CopyTo(sink2);
	sink2.MessageEnd();

	// Suppose we want to store the public key separately,
	// possibly because we will be sending the public key to a third party.
	RSAFunction pubkey(privkey);

	Base64Encoder pubkeysink(new FileSink("master-pubkey.txt"));
	pubkey.DEREncode(pubkeysink);
	pubkeysink.MessageEnd();

}

int main()
{
	GenKeyPair();
}

<commit_msg>Clarify question prompts<commit_after>//g++ genmasterpair.cpp -lcrypto++ -o genmasterpair

#include <string>
using namespace std;
#include <crypto++/rsa.h>
#include <crypto++/osrng.h>
#include <crypto++/base64.h>
#include <crypto++/files.h>
#include <crypto++/aes.h>
#include <crypto++/modes.h>
#include <crypto++/ripemd.h>
using namespace CryptoPP;

void GenKeyPair()
{
	cout << "Enter new master key password" << endl;
	string pass;
	cin >> pass;

	// InvertibleRSAFunction is used directly only because the private key
	// won't actually be used to perform any cryptographic operation;
	// otherwise, an appropriate typedef'ed type from rsa.h would have been used.
	AutoSeededRandomPool rng;
	InvertibleRSAFunction privkey;
	privkey.Initialize(rng, 1024*8);

	// With the current version of Crypto++, MessageEnd() needs to be called
	// explicitly because Base64Encoder doesn't flush its buffer on destruction.
	string privKeyDer;
	StringSink privKeyDerSink(privKeyDer);
	privkey.DEREncode(privKeyDerSink);

	//Hash the pass phrase to create 128 bit key
	string hashedPass;
	RIPEMD128 hash;
	StringSource(pass, true, new HashFilter(hash, new StringSink(hashedPass)));

	// Generate a random IV
	byte iv[AES::BLOCKSIZE];
	rng.GenerateBlock(iv, AES::BLOCKSIZE);

	//Encrypt private key
	CFB_Mode<AES>::Encryption cfbEncryption((const unsigned char*)hashedPass.c_str(), hashedPass.length(), iv);
	byte encPrivKey[privKeyDer.length()+1];
	cfbEncryption.ProcessData(encPrivKey, (const byte*)privKeyDer.c_str(), privKeyDer.length());
	string encPrivKeyStr((char *)encPrivKey, privKeyDer.length());

	//Save private key to file
	StringSource encPrivKeySrc(encPrivKeyStr, true);
	Base64Encoder sink(new FileSink("master-privkey-enc.txt"));
	encPrivKeySrc.CopyTo(sink);
	sink.MessageEnd();

	//Save initialization vector key to file
	StringSource ivStr(iv, AES::BLOCKSIZE, true);
	Base64Encoder sink2(new FileSink("master-privkey-iv.txt"));
	ivStr.CopyTo(sink2);
	sink2.MessageEnd();

	// Suppose we want to store the public key separately,
	// possibly because we will be sending the public key to a third party.
	RSAFunction pubkey(privkey);

	Base64Encoder pubkeysink(new FileSink("master-pubkey.txt"));
	pubkey.DEREncode(pubkeysink);
	pubkeysink.MessageEnd();

}

int main()
{
	GenKeyPair();
}

<|endoftext|>


<commit_before>#ifndef ITERTOOLS_HPP
#define ITERTOOLS_HPP

#include <chain.hpp>
#include <combinations.hpp>
#include <combinations_with_replacement.hpp>
#include <compress.hpp>
#include <count.hpp>
#include <cycle.hpp>
#include <dropwhile.hpp>
#include <enumerate.hpp>
#include <filter.hpp>
#include <filterfalse.hpp>
#include <groupby.hpp>
#include <grouper.hpp>
#include <imap.hpp>
#include <iterator_range.hpp>
#include <iterbase.hpp>
#include <moving_section.hpp>
#include <permutations.hpp>
#include <powerset.hpp>
#include <product.hpp>
#include <range.hpp>
#include <repeat.hpp>
#include <reverse.hpp>
#include <slice.hpp>
#include <sorted.hpp>
#include <takewhile.hpp>
#include <unique_everseen.hpp>
#include <unique_justseen.hpp>
#include <wrap_iter.hpp>
#include <zip.hpp>
#include <zip_longest.hpp>
//not sure if should include "iterator_range.hpp"
//since it's already in everything

#endif

<commit_msg>Removes include of iterbase from itertools.hpp<commit_after>#ifndef ITERTOOLS_HPP
#define ITERTOOLS_HPP

#include <chain.hpp>
#include <combinations.hpp>
#include <combinations_with_replacement.hpp>
#include <compress.hpp>
#include <count.hpp>
#include <cycle.hpp>
#include <dropwhile.hpp>
#include <enumerate.hpp>
#include <filter.hpp>
#include <filterfalse.hpp>
#include <groupby.hpp>
#include <grouper.hpp>
#include <imap.hpp>
#include <iterator_range.hpp>
#include <moving_section.hpp>
#include <permutations.hpp>
#include <powerset.hpp>
#include <product.hpp>
#include <range.hpp>
#include <repeat.hpp>
#include <reverse.hpp>
#include <slice.hpp>
#include <sorted.hpp>
#include <takewhile.hpp>
#include <unique_everseen.hpp>
#include <unique_justseen.hpp>
#include <wrap_iter.hpp>
#include <zip.hpp>
#include <zip_longest.hpp>
//not sure if should include "iterator_range.hpp"
//since it's already in everything

#endif

<|endoftext|>


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

#include <benchmark/benchmark.h>

#include <memory>
#include <string>
#include <vector>

#include "lifecycle_msgs/msg/state.hpp"
#include "lifecycle_msgs/srv/change_state.hpp"
#include "lifecycle_msgs/srv/get_available_states.hpp"
#include "lifecycle_msgs/srv/get_available_transitions.hpp"
#include "lifecycle_msgs/srv/get_state.hpp"
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"

/**
 * Benchmarks for measuring performance of a lifecycle_node client.
 *
 * A service client of a lifecycle node is not a class that's explicitly part of ros2 core,
 * but it is the expected interface for interacting with a lifecycle node, so for that reason
 * this benchmark exists.
 */

using namespace std::chrono_literals;
constexpr char const * lifecycle_node_name = "lc_talker";

constexpr char const * node_get_state_topic = "/lc_talker/get_state";
constexpr char const * node_change_state_topic = "/lc_talker/change_state";
constexpr char const * node_get_available_states_topic = "/lc_talker/get_available_states";
constexpr char const * node_get_available_transitions_topic =
  "/lc_talker/get_available_transitions";
constexpr char const * node_get_transition_graph_topic =
  "/lc_talker/get_transition_graph";
const lifecycle_msgs::msg::State unknown_state = lifecycle_msgs::msg::State();
class LifecycleServiceClient : public rclcpp::Node
{
public:
  explicit LifecycleServiceClient(std::string node_name)
  : Node(node_name)
  {
    client_get_available_states_ = this->create_client<lifecycle_msgs::srv::GetAvailableStates>(
      node_get_available_states_topic);
    client_get_available_transitions_ =
      this->create_client<lifecycle_msgs::srv::GetAvailableTransitions>(
      node_get_available_transitions_topic);
    client_get_transition_graph_ =
      this->create_client<lifecycle_msgs::srv::GetAvailableTransitions>(
      node_get_transition_graph_topic);
    client_get_state_ = this->create_client<lifecycle_msgs::srv::GetState>(
      node_get_state_topic);
    client_change_state_ = this->create_client<lifecycle_msgs::srv::ChangeState>(
      node_change_state_topic);
  }

  lifecycle_msgs::msg::State
  get_state(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetState::Request>();

    if (!client_get_state_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_state_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get state request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }
    return future_result.get()->current_state;
  }

  bool
  change_state(std::uint8_t transition, std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::ChangeState::Request>();
    request->transition.id = transition;

    if (!client_change_state_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_change_state_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Change state request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->success;
  }

  std::vector<lifecycle_msgs::msg::State>
  get_available_states(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableStates::Request>();

    if (!client_get_available_states_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_available_states_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get available states request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_states;
  }

  std::vector<lifecycle_msgs::msg::TransitionDescription>
  get_available_transitions(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableTransitions::Request>();

    if (!client_get_available_transitions_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_available_transitions_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get available transitions request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_transitions;
  }

  std::vector<lifecycle_msgs::msg::TransitionDescription>
  get_transition_graph(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableTransitions::Request>();

    if (!client_get_transition_graph_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_transition_graph_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get transition graph request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_transitions;
  }

private:
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableStates>>
  client_get_available_states_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableTransitions>>
  client_get_available_transitions_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableTransitions>>
  client_get_transition_graph_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetState>> client_get_state_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::ChangeState>> client_change_state_;
};

class BenchmarkLifecycleClient : public performance_test_fixture::PerformanceTest
{
public:
  void SetUp(benchmark::State & state)
  {
    rclcpp::init(0, nullptr);
    lifecycle_node = std::make_shared<rclcpp_lifecycle::LifecycleNode>(lifecycle_node_name);
    lifecycle_client = std::make_shared<LifecycleServiceClient>("lifecycle_client");
    executor = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
    executor->add_node(lifecycle_node->get_node_base_interface());
    executor->add_node(lifecycle_client->get_node_base_interface());
    spinner_ = std::thread(&rclcpp::executors::SingleThreadedExecutor::spin, executor);
    performance_test_fixture::PerformanceTest::SetUp(state);
  }

  void TearDown(benchmark::State & state)
  {
    performance_test_fixture::PerformanceTest::TearDown(state);
    executor->cancel();
    spinner_.join();
    lifecycle_node.reset();
    lifecycle_client.reset();
    rclcpp::shutdown();
  }

protected:
  std::shared_ptr<rclcpp_lifecycle::LifecycleNode> lifecycle_node;
  std::shared_ptr<LifecycleServiceClient> lifecycle_client;
  std::shared_ptr<rclcpp::executors::SingleThreadedExecutor> executor;
  std::thread spinner_;
};

BENCHMARK_F(BenchmarkLifecycleClient, get_state)(benchmark::State & state) {
  for (auto _ : state) {
    const auto lifecycle_state = lifecycle_client->get_state();
    if (lifecycle_state.id != lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED) {
      const std::string msg =
        std::string("Expected state did not match actual: ") +
        std::to_string(lifecycle_state.id);
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(lifecycle_state);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, change_state)(benchmark::State & state) {
  bool success =
    lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_CONFIGURE);
  if (!success) {
    state.SkipWithError("Transition to configured state failed");
  }

  reset_heap_counters();
  for (auto _ : state) {
    success =
      lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_ACTIVATE);
    if (!success) {
      state.SkipWithError("Transition to active state failed");
    }

    success =
      lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_DEACTIVATE);
    if (!success) {
      state.SkipWithError("Transition to inactive state failed");
    }
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_available_states)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_states = 11u;
    const auto states = lifecycle_client->get_available_states();
    if (states.size() != expected_states) {
      const std::string msg =
        std::string("Expected number of states did not match actual: ") +
        std::to_string(states.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(states);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_available_transitions)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_transitions = 2u;
    const auto transitions = lifecycle_client->get_available_transitions();
    if (transitions.size() != expected_transitions) {
      const std::string msg =
        std::string("Expected number of transitions did not match actual: ") +
        std::to_string(transitions.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(transitions);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_transition_graph)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_transitions = 25u;
    const auto transitions = lifecycle_client->get_transition_graph();
    if (transitions.size() != expected_transitions) {
      const std::string msg =
        std::string("Expected number of transitions did not match actual: ") +
        std::to_string(transitions.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(transitions);
    benchmark::ClobberMemory();
  }
}
<commit_msg>Fix destruction order in lifecycle benchmark (#1675)<commit_after>// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <benchmark/benchmark.h>

#include <memory>
#include <string>
#include <vector>

#include "lifecycle_msgs/msg/state.hpp"
#include "lifecycle_msgs/srv/change_state.hpp"
#include "lifecycle_msgs/srv/get_available_states.hpp"
#include "lifecycle_msgs/srv/get_available_transitions.hpp"
#include "lifecycle_msgs/srv/get_state.hpp"
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"

/**
 * Benchmarks for measuring performance of a lifecycle_node client.
 *
 * A service client of a lifecycle node is not a class that's explicitly part of ros2 core,
 * but it is the expected interface for interacting with a lifecycle node, so for that reason
 * this benchmark exists.
 */

using namespace std::chrono_literals;
constexpr char const * lifecycle_node_name = "lc_talker";

constexpr char const * node_get_state_topic = "/lc_talker/get_state";
constexpr char const * node_change_state_topic = "/lc_talker/change_state";
constexpr char const * node_get_available_states_topic = "/lc_talker/get_available_states";
constexpr char const * node_get_available_transitions_topic =
  "/lc_talker/get_available_transitions";
constexpr char const * node_get_transition_graph_topic =
  "/lc_talker/get_transition_graph";
const lifecycle_msgs::msg::State unknown_state = lifecycle_msgs::msg::State();
class LifecycleServiceClient : public rclcpp::Node
{
public:
  explicit LifecycleServiceClient(std::string node_name)
  : Node(node_name)
  {
    client_get_available_states_ = this->create_client<lifecycle_msgs::srv::GetAvailableStates>(
      node_get_available_states_topic);
    client_get_available_transitions_ =
      this->create_client<lifecycle_msgs::srv::GetAvailableTransitions>(
      node_get_available_transitions_topic);
    client_get_transition_graph_ =
      this->create_client<lifecycle_msgs::srv::GetAvailableTransitions>(
      node_get_transition_graph_topic);
    client_get_state_ = this->create_client<lifecycle_msgs::srv::GetState>(
      node_get_state_topic);
    client_change_state_ = this->create_client<lifecycle_msgs::srv::ChangeState>(
      node_change_state_topic);
  }

  lifecycle_msgs::msg::State
  get_state(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetState::Request>();

    if (!client_get_state_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_state_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get state request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }
    return future_result.get()->current_state;
  }

  bool
  change_state(std::uint8_t transition, std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::ChangeState::Request>();
    request->transition.id = transition;

    if (!client_change_state_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_change_state_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Change state request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->success;
  }

  std::vector<lifecycle_msgs::msg::State>
  get_available_states(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableStates::Request>();

    if (!client_get_available_states_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_available_states_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get available states request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_states;
  }

  std::vector<lifecycle_msgs::msg::TransitionDescription>
  get_available_transitions(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableTransitions::Request>();

    if (!client_get_available_transitions_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_available_transitions_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get available transitions request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_transitions;
  }

  std::vector<lifecycle_msgs::msg::TransitionDescription>
  get_transition_graph(std::chrono::seconds time_out = 1s)
  {
    auto request = std::make_shared<lifecycle_msgs::srv::GetAvailableTransitions::Request>();

    if (!client_get_transition_graph_->wait_for_service(time_out)) {
      throw std::runtime_error("Wait for service timed out");
    }

    auto future_result = client_get_transition_graph_->async_send_request(request);
    auto future_status = future_result.wait_for(time_out);

    if (future_status != std::future_status::ready) {
      throw std::runtime_error("Get transition graph request failed");
    }

    if (!future_result.valid()) {
      throw std::runtime_error("Future result was not valid");
    }

    return future_result.get()->available_transitions;
  }

private:
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableStates>>
  client_get_available_states_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableTransitions>>
  client_get_available_transitions_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetAvailableTransitions>>
  client_get_transition_graph_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::GetState>> client_get_state_;
  std::shared_ptr<rclcpp::Client<lifecycle_msgs::srv::ChangeState>> client_change_state_;
};

class BenchmarkLifecycleClient : public performance_test_fixture::PerformanceTest
{
public:
  void SetUp(benchmark::State & state)
  {
    rclcpp::init(0, nullptr);
    lifecycle_node = std::make_shared<rclcpp_lifecycle::LifecycleNode>(lifecycle_node_name);
    lifecycle_client = std::make_shared<LifecycleServiceClient>("lifecycle_client");
    executor = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
    executor->add_node(lifecycle_node->get_node_base_interface());
    executor->add_node(lifecycle_client->get_node_base_interface());
    spinner_ = std::thread(&rclcpp::executors::SingleThreadedExecutor::spin, executor);
    performance_test_fixture::PerformanceTest::SetUp(state);
  }

  void TearDown(benchmark::State & state)
  {
    performance_test_fixture::PerformanceTest::TearDown(state);
    executor->cancel();
    spinner_.join();
    executor.reset();
    lifecycle_client.reset();
    lifecycle_node.reset();
    rclcpp::shutdown();
  }

protected:
  std::shared_ptr<rclcpp_lifecycle::LifecycleNode> lifecycle_node;
  std::shared_ptr<LifecycleServiceClient> lifecycle_client;
  std::shared_ptr<rclcpp::executors::SingleThreadedExecutor> executor;
  std::thread spinner_;
};

BENCHMARK_F(BenchmarkLifecycleClient, get_state)(benchmark::State & state) {
  for (auto _ : state) {
    const auto lifecycle_state = lifecycle_client->get_state();
    if (lifecycle_state.id != lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED) {
      const std::string msg =
        std::string("Expected state did not match actual: ") +
        std::to_string(lifecycle_state.id);
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(lifecycle_state);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, change_state)(benchmark::State & state) {
  bool success =
    lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_CONFIGURE);
  if (!success) {
    state.SkipWithError("Transition to configured state failed");
  }

  reset_heap_counters();
  for (auto _ : state) {
    success =
      lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_ACTIVATE);
    if (!success) {
      state.SkipWithError("Transition to active state failed");
    }

    success =
      lifecycle_client->change_state(lifecycle_msgs::msg::Transition::TRANSITION_DEACTIVATE);
    if (!success) {
      state.SkipWithError("Transition to inactive state failed");
    }
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_available_states)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_states = 11u;
    const auto states = lifecycle_client->get_available_states();
    if (states.size() != expected_states) {
      const std::string msg =
        std::string("Expected number of states did not match actual: ") +
        std::to_string(states.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(states);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_available_transitions)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_transitions = 2u;
    const auto transitions = lifecycle_client->get_available_transitions();
    if (transitions.size() != expected_transitions) {
      const std::string msg =
        std::string("Expected number of transitions did not match actual: ") +
        std::to_string(transitions.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(transitions);
    benchmark::ClobberMemory();
  }
}

BENCHMARK_F(BenchmarkLifecycleClient, get_transition_graph)(benchmark::State & state) {
  for (auto _ : state) {
    constexpr size_t expected_transitions = 25u;
    const auto transitions = lifecycle_client->get_transition_graph();
    if (transitions.size() != expected_transitions) {
      const std::string msg =
        std::string("Expected number of transitions did not match actual: ") +
        std::to_string(transitions.size());
      state.SkipWithError(msg.c_str());
    }
    benchmark::DoNotOptimize(transitions);
    benchmark::ClobberMemory();
  }
}
<|endoftext|>