text:
/*=============================================================================
    Copyright (c) 2017 Paul Fultz II
    placeholders.cpp
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <boost/hof/placeholders.hpp>
#include "test.hpp"
#include <sstream>

// TODO: Test assign operators

#if BOOST_HOF_HAS_STATIC_TEST_CHECK
#define BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR constexpr
#else
#define BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR
#endif

struct square
{
    template<class T>
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto operator()(T x) const BOOST_HOF_RETURNS(x*x);
};

#define CHECK_DEFAULT_CONSTRUCTION_OP(op, name) \
    static_assert(boost::hof::detail::is_default_constructible<boost::hof::operators::name>::value, "Operator not default constructible");

#if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION
#define PLACEHOLDER_CHECK(...) \
    BOOST_HOF_STATIC_TEST_CHECK(__VA_ARGS__); \
    BOOST_HOF_TEST_CHECK(__VA_ARGS__); \
    static_assert(noexcept(__VA_ARGS__), "noexcept placeholders")
#else
#define PLACEHOLDER_CHECK(...) \
    BOOST_HOF_STATIC_TEST_CHECK(__VA_ARGS__); \
    BOOST_HOF_TEST_CHECK(__VA_ARGS__)
#endif

BOOST_HOF_TEST_CASE()
{
    static_assert(boost::hof::detail::is_default_constructible<boost::hof::placeholder<1>>::value, "Placeholder not default constructible");
    static_assert(boost::hof::detail::is_default_constructible<boost::hof::placeholder<2>>::value, "Placeholder not default constructible");
    static_assert(boost::hof::detail::is_default_constructible<boost::hof::placeholder<3>>::value, "Placeholder not default constructible");

    BOOST_HOF_FOREACH_BINARY_OP(CHECK_DEFAULT_CONSTRUCTION_OP)
    BOOST_HOF_FOREACH_ASSIGN_OP(CHECK_DEFAULT_CONSTRUCTION_OP)
    BOOST_HOF_FOREACH_UNARY_OP(CHECK_DEFAULT_CONSTRUCTION_OP)
}

BOOST_HOF_TEST_CASE()
{
    auto simple_print = boost::hof::reveal(std::ref(std::cout) << boost::hof::_);
    simple_print("Hello");
}

BOOST_HOF_TEST_CASE()
{
    std::stringstream ss;
    auto simple_print = boost::hof::reveal(std::ref(ss) << boost::hof::_);
    simple_print("Hello");
    BOOST_HOF_TEST_CHECK(ss.str() == "Hello");
}

BOOST_HOF_TEST_CASE()
{
    const auto x_square_add = 2 + (4*4);
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_square_add = boost::hof::_1 + boost::hof::lazy(square())(boost::hof::_2);
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_square_add)>::value, "Not copyable");
#endif
    PLACEHOLDER_CHECK(f_square_add(2, 4) == x_square_add);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_invoke_2 = boost::hof::_1(3);
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_invoke_2)>::value, "Not copyable");
#endif
    PLACEHOLDER_CHECK(f_invoke_2(square()) == 9);
}

BOOST_HOF_TEST_CASE()
{
    const auto x_add = 2 + 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_add = boost::hof::_1 + boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_add)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_add)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_add(2, 1) == x_add);

    const auto x_subtract = 2 - 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_subtract = boost::hof::_1 - boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_subtract)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_subtract)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_subtract(2, 1) == x_subtract);

    const auto x_multiply = 2 * 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_multiply = boost::hof::_1 * boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_multiply)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_multiply)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_multiply(2, 1) == x_multiply);

    const auto x_divide = 2 / 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_divide = boost::hof::_1 / boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_divide)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_divide)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_divide(2, 1) == x_divide);

    const auto x_remainder = 2 % 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_remainder = boost::hof::_1 % boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_remainder)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_remainder)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_remainder(2, 1) == x_remainder);

    const auto x_shift_right = 2 >> 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_right = boost::hof::_1 >> boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_right)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_shift_right)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_shift_right(2, 1) == x_shift_right);

    const auto x_shift_left = 2 << 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_left = boost::hof::_1 << boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_left)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_shift_left)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_shift_left(2, 1) == x_shift_left);

    const auto x_greater_than = 2 > 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than = boost::hof::_1 > boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_greater_than)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_greater_than(2, 1) == x_greater_than);

    const auto x_less_than = 2 < 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than = boost::hof::_1 < boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_less_than)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_less_than(2, 1) == x_less_than);

    const auto x_less_than_equal = 2 <= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than_equal = boost::hof::_1 <= boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_less_than_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_less_than_equal(2, 1) == x_less_than_equal);

    const auto x_greater_than_equal = 2 >= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than_equal = boost::hof::_1 >= boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_greater_than_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_greater_than_equal(2, 1) == x_greater_than_equal);

    const auto x_equal = 2 == 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_equal = boost::hof::_1 == boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_equal(2, 1) == x_equal);

    const auto x_not_equal = 2 != 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_equal = boost::hof::_1 != boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_not_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_not_equal(2, 1) == x_not_equal);

    const auto x_bit_and = 2 & 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_and = boost::hof::_1 & boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_and)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_bit_and)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_bit_and(2, 1) == x_bit_and);

    const auto x_xor_ = 2 ^ 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_xor_ = boost::hof::_1 ^ boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_xor_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_xor_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_xor_(2, 1) == x_xor_);

    const auto x_bit_or = 2 | 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_or = boost::hof::_1 | boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_or)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_bit_or)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_bit_or(2, 1) == x_bit_or);

    const auto x_and_ = true && false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_and_ = boost::hof::_1 && boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_and_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_and_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_and_(true, false) == x_and_);

    const auto x_or_ = true;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_or_ = boost::hof::_1 || boost::hof::_2;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_or_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_or_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_or_(true, false) == x_or_);
}

BOOST_HOF_TEST_CASE()
{

    const auto x_not_ = !false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_ = !boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_not_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_not_(false) == x_not_);

    const auto x_not_0 = !0;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_0 = !boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_0)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_not_0)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_not_0(0) == x_not_0);

    const auto x_compl_ = ~2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_compl_ = ~boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_compl_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_compl_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_compl_(2) == x_compl_);

    const auto x_unary_plus = +2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_unary_plus = +boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_unary_plus)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_unary_plus)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_unary_plus(2) == x_unary_plus);

    const auto x_unary_subtract = -2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_unary_subtract = -boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_unary_subtract)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_unary_subtract)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_unary_subtract(2) == x_unary_subtract);

    const auto x_dereference = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_dereference = *boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_dereference)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_dereference)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_dereference(&x_dereference) == x_dereference);

    // TODO: Test BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR increment and decrement
#ifndef _MSC_VER
    auto x_increment = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_increment = ++boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_increment)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_increment)>::value, "Not default constructible");
    f_increment(x_increment);
    BOOST_HOF_TEST_CHECK(x_increment == 3);

    auto x_decrement = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_decrement = --boost::hof::_1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_decrement)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_decrement)>::value, "Not default constructible");
    f_decrement(x_decrement);
    BOOST_HOF_TEST_CHECK(x_decrement == 1);
#endif

    // TODO: Test post increment and decrement
}

BOOST_HOF_TEST_CASE()
{
    const auto x_add = 2 + 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_add = boost::hof::_ + boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_add)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_add)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_add(2, 1) == x_add);

    const auto x_subtract = 2 - 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_subtract = boost::hof::_ - boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_subtract)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_subtract)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_subtract(2, 1) == x_subtract);

    const auto x_multiply = 2 * 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_multiply = boost::hof::_ * boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_multiply)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_multiply)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_multiply(2, 1) == x_multiply);

    const auto x_divide = 2 / 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_divide = boost::hof::_ / boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_divide)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_divide)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_divide(2, 1) == x_divide);

    const auto x_remainder = 2 % 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_remainder = boost::hof::_ % boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_remainder)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_remainder)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_remainder(2, 1) == x_remainder);

    const auto x_shift_right = 2 >> 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_right = boost::hof::_ >> boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_right)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_shift_right)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_shift_right(2, 1) == x_shift_right);

    const auto x_shift_left = 2 << 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_left = boost::hof::_ << boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_left)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_shift_left)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_shift_left(2, 1) == x_shift_left);

    const auto x_greater_than = 2 > 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than = boost::hof::_ > boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_greater_than)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_greater_than(2, 1) == x_greater_than);

    const auto x_less_than = 2 < 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than = boost::hof::_ < boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_less_than)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_less_than(2, 1) == x_less_than);

    const auto x_less_than_equal = 2 <= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than_equal = boost::hof::_ <= boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_less_than_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_less_than_equal(2, 1) == x_less_than_equal);

    const auto x_greater_than_equal = 2 >= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than_equal = boost::hof::_ >= boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_greater_than_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_greater_than_equal(2, 1) == x_greater_than_equal);

    const auto x_equal = 2 == 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_equal = boost::hof::_ == boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_equal(2, 1) == x_equal);

    const auto x_not_equal = 2 != 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_equal = boost::hof::_ != boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_equal)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_not_equal)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_not_equal(2, 1) == x_not_equal);

    const auto x_bit_and = 2 & 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_and = boost::hof::_ & boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_and)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_bit_and)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_bit_and(2, 1) == x_bit_and);

    const auto x_xor_ = 2 ^ 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_xor_ = boost::hof::_ ^ boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_xor_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_xor_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_xor_(2, 1) == x_xor_);

    const auto x_bit_or = 2 | 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_or = boost::hof::_ | boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_or)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_bit_or)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_bit_or(2, 1) == x_bit_or);

    const auto x_and_ = true && false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_and_ = boost::hof::_ && boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_and_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_and_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_and_(true, false) == x_and_);

    const auto x_or_ = true;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_or_ = boost::hof::_ || boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_or_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_or_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_or_(true, false) == x_or_);
}

BOOST_HOF_TEST_CASE()
{
    const auto x_add = 2 + 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_add = 2 + boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_add)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_add)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_add(1) == x_add);

    const auto x_subtract = 2 - 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_subtract = 2 - boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_subtract)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_subtract)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_subtract(1) == x_subtract);

    const auto x_multiply = 2 * 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_multiply = 2 * boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_multiply)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_multiply)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_multiply(1) == x_multiply);

    const auto x_divide = 2 / 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_divide = 2 / boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_divide)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_divide)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_divide(1) == x_divide);

    const auto x_remainder = 2 % 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_remainder = 2 % boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_remainder)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_remainder)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_remainder(1) == x_remainder);

    const auto x_shift_right = 2 >> 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_right = 2 >> boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_right)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_shift_right)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_shift_right(1) == x_shift_right);

    const auto x_shift_left = 2 << 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_left = 2 << boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_left)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_shift_left)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_shift_left(1) == x_shift_left);

    const auto x_greater_than = 2 > 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than = 2 > boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_greater_than)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_greater_than(1) == x_greater_than);

    const auto x_less_than = 2 < 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than = 2 < boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_less_than)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_less_than(1) == x_less_than);

    const auto x_less_than_equal = 2 <= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than_equal = 2 <= boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_less_than_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_less_than_equal(1) == x_less_than_equal);

    const auto x_greater_than_equal = 2 >= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than_equal = 2 >= boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_greater_than_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_greater_than_equal(1) == x_greater_than_equal);

    const auto x_equal = 2 == 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_equal = 2 == boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_equal(1) == x_equal);

    const auto x_not_equal = 2 != 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_equal = 2 != boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_not_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_not_equal(1) == x_not_equal);

    const auto x_bit_and = 2 & 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_and = 2 & boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_and)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_bit_and)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_bit_and(1) == x_bit_and);

    const auto x_xor_ = 2 ^ 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_xor_ = 2 ^ boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_xor_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_xor_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_xor_(1) == x_xor_);

    const auto x_bit_or = 2 | 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_or = 2 | boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_or)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_bit_or)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_bit_or(1) == x_bit_or);

    const auto x_and_ = true && false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_and_ = true && boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_and_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_and_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_and_(false) == x_and_);

    const auto x_or_ = true;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_or_ = true || boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_or_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_or_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_or_(false) == x_or_);
}

BOOST_HOF_TEST_CASE()
{
    const auto x_add = 2 + 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_add = boost::hof::_ + 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_add)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_add)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_add(2) == x_add);

    const auto x_subtract = 2 - 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_subtract = boost::hof::_ - 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_subtract)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_subtract)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_subtract(2) == x_subtract);

    const auto x_multiply = 2 * 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_multiply = boost::hof::_ * 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_multiply)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_multiply)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_multiply(2) == x_multiply);

    const auto x_divide = 2 / 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_divide = boost::hof::_ / 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_divide)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_divide)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_divide(2) == x_divide);

    const auto x_remainder = 2 % 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_remainder = boost::hof::_ % 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_remainder)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_remainder)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_remainder(2) == x_remainder);

    const auto x_shift_right = 2 >> 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_right = boost::hof::_ >> 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_right)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_shift_right)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_shift_right(2) == x_shift_right);

    const auto x_shift_left = 2 << 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_shift_left = boost::hof::_ << 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_shift_left)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_shift_left)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_shift_left(2) == x_shift_left);

    const auto x_greater_than = 2 > 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than = boost::hof::_ > 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_greater_than)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_greater_than(2) == x_greater_than);

    const auto x_less_than = 2 < 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than = boost::hof::_ < 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_less_than)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_less_than(2) == x_less_than);

    const auto x_less_than_equal = 2 <= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_less_than_equal = boost::hof::_ <= 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_less_than_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_less_than_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_less_than_equal(2) == x_less_than_equal);

    const auto x_greater_than_equal = 2 >= 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_greater_than_equal = boost::hof::_ >= 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_greater_than_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_greater_than_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_greater_than_equal(2) == x_greater_than_equal);

    const auto x_equal = 2 == 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_equal = boost::hof::_ == 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_equal(2) == x_equal);

    const auto x_not_equal = 2 != 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_equal = boost::hof::_ != 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_equal)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_not_equal)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_not_equal(2) == x_not_equal);

    const auto x_bit_and = 2 & 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_and = boost::hof::_ & 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_and)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_bit_and)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_bit_and(2) == x_bit_and);

    const auto x_xor_ = 2 ^ 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_xor_ = boost::hof::_ ^ 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_xor_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_xor_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_xor_(2) == x_xor_);

    const auto x_bit_or = 2 | 1;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_bit_or = boost::hof::_ | 1;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_bit_or)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_bit_or)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_bit_or(2) == x_bit_or);

    const auto x_and_ = true && false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_and_ = boost::hof::_ && false;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_and_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_and_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_and_(true) == x_and_);

    const auto x_or_ = true;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_or_ = boost::hof::_ || false;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_or_)>::value, "Not copyable");
#endif
    static_assert(!boost::hof::detail::is_default_constructible<decltype(f_or_)>::value, "default constructible");
    PLACEHOLDER_CHECK(f_or_(true) == x_or_);
}

BOOST_HOF_TEST_CASE()
{

    const auto x_not_ = !false;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_not_ = !boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_not_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_not_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_not_(false) == x_not_);

    const auto x_compl_ = ~2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_compl_ = ~boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_compl_)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_compl_)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_compl_(2) == x_compl_);

    const auto x_unary_plus = +2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_unary_plus = +boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_unary_plus)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_unary_plus)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_unary_plus(2) == x_unary_plus);

    const auto x_unary_subtract = -2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_unary_subtract = -boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_unary_subtract)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_unary_subtract)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_unary_subtract(2) == x_unary_subtract);

    const auto x_dereference = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_dereference = *boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_dereference)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_dereference)>::value, "Not default constructible");
    PLACEHOLDER_CHECK(f_dereference(&x_dereference) == x_dereference);

    // TODO: Test constexpr increment and decrement
#ifndef _MSC_VER
    auto x_increment = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_increment = ++boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_increment)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_increment)>::value, "Not default constructible");
    f_increment(x_increment);
    BOOST_HOF_TEST_CHECK(x_increment == 3);

    auto x_decrement = 2;
    BOOST_HOF_PLACEHOLDER_TEST_CONSTEXPR auto f_decrement = --boost::hof::_;
#if defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ > 6
    static_assert(std::is_copy_constructible<decltype(f_decrement)>::value, "Not copyable");
#endif
    static_assert(boost::hof::detail::is_default_constructible<decltype(f_decrement)>::value, "Not default constructible");
    f_decrement(x_decrement);
    BOOST_HOF_TEST_CHECK(x_decrement == 1);
#endif

    // TODO: Test post increment and decrement
}


text:
/**
*    Copyright (C) 2012 10gen Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*    As a special exception, the copyright holders give permission to link the
*    code of portions of this program with the OpenSSL library under certain
*    conditions as described in each individual source file and distribute
*    linked combinations including the program with the OpenSSL library. You
*    must comply with the GNU Affero General Public License in all respects for
*    all of the code used other than as permitted herein. If you modify file(s)
*    with this exception, you may extend this exception to your version of the
*    file(s), but you are not obligated to do so. If you do not wish to do so,
*    delete this exception statement from your version. If you delete this
*    exception statement from all source files in the program, then also delete
*    it in the license file.
*/

#include "mongo/platform/basic.h"

#include "mongo/db/auth/authorization_manager.h"

#include <boost/thread/mutex.hpp>
#include <memory>
#include <string>
#include <vector>

#include "mongo/base/init.h"
#include "mongo/base/status.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/bson/mutable/element.h"
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/authz_documents_update_guard.h"
#include "mongo/db/auth/authz_manager_external_state.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/role_graph.h"
#include "mongo/db/auth/user.h"
#include "mongo/db/auth/user_document_parser.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/auth/user_name_hash.h"
#include "mongo/db/jsobj.h"
#include "mongo/platform/compiler.h"
#include "mongo/platform/unordered_map.h"
#include "mongo/util/log.h"
#include "mongo/util/map_util.h"
#include "mongo/util/mongoutils/str.h"

namespace mongo {

    AuthInfo internalSecurity;

    MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, MONGO_NO_PREREQUISITES)(
            InitializerContext* context) {

        User* user = new User(UserName("__system", "local"));

        user->incrementRefCount(); // Pin this user so the ref count never drops below 1.
        ActionSet allActions;
        allActions.addAllActions();
        PrivilegeVector privileges;
        RoleGraph::generateUniversalPrivileges(&privileges);
        user->addPrivileges(privileges);
        internalSecurity.user = user;

        return Status::OK();
    }

    const std::string AuthorizationManager::USER_NAME_FIELD_NAME = "name";
    const std::string AuthorizationManager::USER_SOURCE_FIELD_NAME = "db";
    const std::string AuthorizationManager::ROLE_NAME_FIELD_NAME = "name";
    const std::string AuthorizationManager::ROLE_SOURCE_FIELD_NAME = "db";
    const std::string AuthorizationManager::PASSWORD_FIELD_NAME = "pwd";
    const std::string AuthorizationManager::V1_USER_NAME_FIELD_NAME = "user";
    const std::string AuthorizationManager::V1_USER_SOURCE_FIELD_NAME = "userSource";

    const NamespaceString AuthorizationManager::adminCommandNamespace("admin.$cmd");
    const NamespaceString AuthorizationManager::rolesCollectionNamespace("admin.system.roles");
    const NamespaceString AuthorizationManager::usersCollectionNamespace("admin.system.users");
    const NamespaceString AuthorizationManager::versionCollectionNamespace("admin.system.version");

    bool AuthorizationManager::_doesSupportOldStylePrivileges = true;

    AuthorizationManager::AuthorizationManager(AuthzManagerExternalState* externalState) :
        _authEnabled(false), _externalState(externalState) {

        setAuthorizationVersion(2);
    }

    AuthorizationManager::~AuthorizationManager() {
        for (unordered_map<UserName, User*>::iterator it = _userCache.begin();
                it != _userCache.end(); ++it) {
            if (it->second != internalSecurity.user) {
                // The internal user should never be deleted.
                delete it->second ;
            }
        }
    }

    Status AuthorizationManager::setAuthorizationVersion(int version) {
        boost::lock_guard<boost::mutex> lk(_lock);

        if (version != 1 && version != 2) {
            return Status(ErrorCodes::UnsupportedFormat,
                          mongoutils::str::stream() <<
                                  "Unrecognized authorization format version: " <<
                                  version);
        }

        _version = version;
        return Status::OK();
    }

    int AuthorizationManager::getAuthorizationVersion() {
        boost::lock_guard<boost::mutex> lk(_lock);
        return _getVersion_inlock();
    }

    void AuthorizationManager::setSupportOldStylePrivilegeDocuments(bool enabled) {
        _doesSupportOldStylePrivileges = enabled;
    }

    bool AuthorizationManager::getSupportOldStylePrivilegeDocuments() {
        return _doesSupportOldStylePrivileges;
    }

    void AuthorizationManager::setAuthEnabled(bool enabled) {
        _authEnabled = enabled;
    }

    bool AuthorizationManager::isAuthEnabled() const {
        return _authEnabled;
    }

    bool AuthorizationManager::hasAnyPrivilegeDocuments() const {
        return _externalState->hasAnyPrivilegeDocuments();
    }

    Status AuthorizationManager::insertPrivilegeDocument(const std::string& dbname,
                                                         const BSONObj& userObj,
                                                         const BSONObj& writeConcern) const {
        return _externalState->insertPrivilegeDocument(dbname, userObj, writeConcern);
    }

    Status AuthorizationManager::updatePrivilegeDocument(const UserName& user,
                                                         const BSONObj& updateObj,
                                                         const BSONObj& writeConcern) const {
        return _externalState->updatePrivilegeDocument(user, updateObj, writeConcern);
    }

    Status AuthorizationManager::removePrivilegeDocuments(const BSONObj& query,
                                                          const BSONObj& writeConcern,
                                                          int* numRemoved) const {
        return _externalState->removePrivilegeDocuments(query, writeConcern, numRemoved);
    }

    Status AuthorizationManager::removeRoleDocuments(const BSONObj& query,
                                                     const BSONObj& writeConcern,
                                                     int* numRemoved) const {
        Status status = _externalState->remove(rolesCollectionNamespace,
                                               query,
                                               writeConcern,
                                               numRemoved);
        if (status.code() == ErrorCodes::UnknownError) {
            return Status(ErrorCodes::RoleModificationFailed, status.reason());
        }
        return status;
    }

    Status AuthorizationManager::insertRoleDocument(const BSONObj& roleObj,
                                                    const BSONObj& writeConcern) const {
        Status status = _externalState->insert(rolesCollectionNamespace,
                                               roleObj,
                                               writeConcern);
        if (status.isOK()) {
            return status;
        }
        if (status.code() == ErrorCodes::DuplicateKey) {
            std::string name = roleObj[AuthorizationManager::ROLE_NAME_FIELD_NAME].String();
            std::string source = roleObj[AuthorizationManager::ROLE_SOURCE_FIELD_NAME].String();
            return Status(ErrorCodes::DuplicateKey,
                          mongoutils::str::stream() << "Role \"" << name << "@" << source <<
                                  "\" already exists");
        }
        if (status.code() == ErrorCodes::UnknownError) {
            return Status(ErrorCodes::RoleModificationFailed, status.reason());
        }
        return status;
    }

    Status AuthorizationManager::updateRoleDocument(const RoleName& role,
                                                    const BSONObj& updateObj,
                                                    const BSONObj& writeConcern) const {
        Status status = _externalState->updateOne(
                rolesCollectionNamespace,
                BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() <<
                     AuthorizationManager::ROLE_SOURCE_FIELD_NAME << role.getDB()),
                updateObj,
                false,
                writeConcern);
        if (status.isOK()) {
            return status;
        }
        if (status.code() == ErrorCodes::NoMatchingDocument) {
            return Status(ErrorCodes::RoleNotFound,
                          mongoutils::str::stream() << "Role " << role.getFullName() <<
                                  " not found");
        }
        if (status.code() == ErrorCodes::UnknownError) {
            return Status(ErrorCodes::RoleModificationFailed, status.reason());
        }
        return status;
    }

    Status AuthorizationManager::queryAuthzDocument(
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj& projection,
            const boost::function<void(const BSONObj&)>& resultProcessor) {
        return _externalState->query(collectionName, query, projection, resultProcessor);
    }

    Status AuthorizationManager::updateAuthzDocuments(const NamespaceString& collectionName,
                                                      const BSONObj& query,
                                                      const BSONObj& updatePattern,
                                                      bool upsert,
                                                      bool multi,
                                                      const BSONObj& writeConcern,
                                                      int* numUpdated) const {
        return _externalState->update(collectionName,
                                      query,
                                      updatePattern,
                                      upsert,
                                      multi,
                                      writeConcern,
                                      numUpdated);
    }

    Status AuthorizationManager::getBSONForPrivileges(const PrivilegeVector& privileges,
                                                      mutablebson::Element resultArray) {
        for (PrivilegeVector::const_iterator it = privileges.begin();
                it != privileges.end(); ++it) {
            std::string errmsg;
            ParsedPrivilege privilege;
            if (!ParsedPrivilege::privilegeToParsedPrivilege(*it, &privilege, &errmsg)) {
                return Status(ErrorCodes::BadValue, errmsg);
            }
            resultArray.appendObject("privileges", privilege.toBSON());
        }
        return Status::OK();
    }

    Status AuthorizationManager::getBSONForRole(RoleGraph* graph,
                                                const RoleName& roleName,
                                                mutablebson::Element result) {
        if (!graph->roleExists(roleName)) {
            return Status(ErrorCodes::RoleNotFound,
                          mongoutils::str::stream() << roleName.getFullName() <<
                                  "does not name an existing role");
        }
        std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole();
        result.appendString("_id", id);
        result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole());
        result.appendString(ROLE_SOURCE_FIELD_NAME, roleName.getDB());

        // Build privileges array
        mutablebson::Element privilegesArrayElement =
                result.getDocument().makeElementArray("privileges");
        result.pushBack(privilegesArrayElement);
        const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName);
        Status status = getBSONForPrivileges(privileges, privilegesArrayElement);
        if (!status.isOK()) {
            return status;
        }

        // Build roles array
        mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles");
        result.pushBack(rolesArrayElement);
        for (RoleNameIterator roles = graph->getDirectSubordinates(roleName);
             roles.more();
             roles.next()) {

            const RoleName& subRole = roles.get();
            mutablebson::Element roleObj = result.getDocument().makeElementObject("");
            roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole());
            roleObj.appendString(ROLE_SOURCE_FIELD_NAME, subRole.getDB());
            rolesArrayElement.pushBack(roleObj);
        }

        return Status::OK();
    }

    static void _initializeUserPrivilegesFromRolesV1(User* user) {
        const User::RoleDataMap& roles = user->getRoles();
        PrivilegeVector privileges;
        for (User::RoleDataMap::const_iterator it = roles.begin(); it != roles.end(); ++it) {
            const User::RoleData& role= it->second;
            if (role.hasRole) {
                RoleGraph::addPrivilegesForBuiltinRole(role.name, &privileges);
            }
        }
        user->addPrivileges(privileges);
    }

    Status AuthorizationManager::_initializeUserFromPrivilegeDocument(
            User* user, const BSONObj& privDoc) {
        V2UserDocumentParser parser;
        std::string userName = parser.extractUserNameFromUserDocument(privDoc);
        if (userName != user->getName().getUser()) {
            return Status(ErrorCodes::BadValue,
                          mongoutils::str::stream() << "User name from privilege document \""
                                  << userName
                                  << "\" doesn't match name of provided User \""
                                  << user->getName().getUser()
                                  << "\"",
                          0);
        }

        Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
        if (!status.isOK()) {
            return status;
        }
        status = parser.initializeUserRolesFromUserDocument(privDoc, user);
        if (!status.isOK()) {
            return status;
        }
        status = parser.initializeUserPrivilegesFromUserDocument(privDoc, user);
        return Status::OK();
    }

    Status AuthorizationManager::getUserDescription(const UserName& userName, BSONObj* result) {
        return _externalState->getUserDescription(userName, result);
    }

    Status AuthorizationManager::getRoleDescription(const RoleName& roleName, BSONObj* result) {
        return _externalState->getRoleDescription(roleName, result);
    }

    Status AuthorizationManager::acquireUser(const UserName& userName, User** acquiredUser) {
        boost::lock_guard<boost::mutex> lk(_lock);
        unordered_map<UserName, User*>::iterator it = _userCache.find(userName);
        if (it != _userCache.end()) {
            fassert(16914, it->second);
            fassert(17003, it->second->isValid());
            fassert(17008, it->second->getRefCount() > 0);
            it->second->incrementRefCount();
            *acquiredUser = it->second;
            return Status::OK();
        }

        if (_getVersion_inlock() != 2) {
            return Status(ErrorCodes::UserNotFound, mongoutils::str::stream() <<
                          "User " << userName.getFullName() << " not found.");
        }

        // Put the new user into an auto_ptr temporarily in case there's an error while
        // initializing the user.
        auto_ptr<User> userHolder(new User(userName));
        User* user = userHolder.get();

        BSONObj userObj;
        Status status = getUserDescription(userName, &userObj);
        if (!status.isOK()) {
            return status;
        }

        status = _initializeUserFromPrivilegeDocument(user, userObj);
        if (!status.isOK()) {
            return status;
        }

        user->incrementRefCount();
        _userCache.insert(make_pair(userName, userHolder.release()));
        *acquiredUser = user;
        return Status::OK();
    }

    void AuthorizationManager::releaseUser(User* user) {
        if (user == internalSecurity.user) {
            return;
        }

        boost::lock_guard<boost::mutex> lk(_lock);
        user->decrementRefCount();
        if (user->getRefCount() == 0) {
            // If it's been invalidated then it's not in the _userCache anymore.
            if (user->isValid()) {
                MONGO_COMPILER_VARIABLE_UNUSED bool erased = _userCache.erase(user->getName());
                dassert(erased);
            }
            delete user;
        }
    }

    void AuthorizationManager::invalidateUser(User* user) {
        boost::lock_guard<boost::mutex> lk(_lock);
        if (!user->isValid()) {
            return;
        }

        unordered_map<UserName, User*>::iterator it = _userCache.find(user->getName());
        massert(17052,
                mongoutils::str::stream() <<
                        "Invalidating cache for user " << user->getName().getFullName() <<
                        " failed as it is not present in the user cache",
                it != _userCache.end() && it->second == user);
        _userCache.erase(it);
        user->invalidate();
    }

    void AuthorizationManager::invalidateUserByName(const UserName& userName) {
        boost::lock_guard<boost::mutex> lk(_lock);

        unordered_map<UserName, User*>::iterator it = _userCache.find(userName);
        if (it == _userCache.end()) {
            return;
        }

        User* user = it->second;
        _userCache.erase(it);
        user->invalidate();
    }

    void AuthorizationManager::invalidateUsersFromDB(const std::string& dbname) {
        boost::lock_guard<boost::mutex> lk(_lock);

        unordered_map<UserName, User*>::iterator it = _userCache.begin();
        while (it != _userCache.end()) {
            User* user = it->second;
            if (user->getName().getDB() == dbname) {
                _userCache.erase(it++);
                user->invalidate();
            } else {
                ++it;
            }
        }
    }

    void AuthorizationManager::addInternalUser(User* user) {
        boost::lock_guard<boost::mutex> lk(_lock);
        _userCache.insert(make_pair(user->getName(), user));
    }

    void AuthorizationManager::invalidateUserCache() {
        boost::lock_guard<boost::mutex> lk(_lock);
        _invalidateUserCache_inlock();
    }

    void AuthorizationManager::_invalidateUserCache_inlock() {
        for (unordered_map<UserName, User*>::iterator it = _userCache.begin();
                it != _userCache.end(); ++it) {
            if (it->second->getName() == internalSecurity.user->getName()) {
                // Don't invalidate the internal user
                continue;
            }
            it->second->invalidate();
            // // Need to decrement ref count and manually clean up User object to prevent memory leaks
            // // since we're pinning all User objects by incrementing their ref count when we
            // // initially populate the cache.
            // // TODO(spencer): remove this once we're not pinning User objects.
            // it->second->decrementRefCount();
            // if (it->second->getRefCount() == 0)
            //     delete it->second;
        }
        _userCache.clear();
        // Make sure the internal user stays in the cache.
        _userCache.insert(make_pair(internalSecurity.user->getName(), internalSecurity.user));
    }

    Status AuthorizationManager::initialize() {
        Status status = _externalState->initialize();
        if (!status.isOK())
            return status;

        if (isAuthEnabled() && getAuthorizationVersion() < 2) {
            // If we are not yet upgraded to the V2 authorization format, build up a read-only
            // view of the V1 style authorization data.
            return _initializeAllV1UserData();
        }

        return Status::OK();
    }

    Status AuthorizationManager::_initializeAllV1UserData() {
        boost::lock_guard<boost::mutex> lk(_lock);
        _invalidateUserCache_inlock();
        V1UserDocumentParser parser;

        try {
            std::vector<std::string> dbNames;
            Status status = _externalState->getAllDatabaseNames(&dbNames);
            if (!status.isOK()) {
                return status;
            }

            for (std::vector<std::string>::iterator dbIt = dbNames.begin();
                    dbIt != dbNames.end(); ++dbIt) {
                std::string dbname = *dbIt;
                std::vector<BSONObj> privDocs;
                Status status = _externalState->getAllV1PrivilegeDocsForDB(dbname, &privDocs);
                if (!status.isOK()) {
                    return status;
                }

                for (std::vector<BSONObj>::iterator docIt = privDocs.begin();
                        docIt != privDocs.end(); ++docIt) {
                    const BSONObj& privDoc = *docIt;

                    std::string source;
                    if (privDoc.hasField("userSource")) {
                        source = privDoc["userSource"].String();
                    } else {
                        source = dbname;
                    }
                    UserName userName(privDoc["user"].String(), source);
                    if (userName == internalSecurity.user->getName()) {
                        // Don't let clients override the internal user by creating a user with the
                        // same name.
                        continue;
                    }

                    User* user = mapFindWithDefault(_userCache, userName, static_cast<User*>(NULL));
                    if (!user) {
                        user = new User(userName);
                        // Make sure the user always has a refCount of at least 1 so it's
                        // effectively "pinned" and will never be removed from the _userCache
                        // unless the whole cache is invalidated.
                        user->incrementRefCount();
                        _userCache.insert(make_pair(userName, user));
                    }

                    if (source == dbname || source == "$external") {
                        status = parser.initializeUserCredentialsFromUserDocument(user,
                                                                                privDoc);
                        if (!status.isOK()) {
                            return status;
                        }
                    }
                    status = parser.initializeUserRolesFromUserDocument(user, privDoc, dbname);
                    if (!status.isOK()) {
                        return status;
                    }
                    _initializeUserPrivilegesFromRolesV1(user);
                }
            }
        } catch (const DBException& e) {
            return e.toStatus();
        } catch (const std::exception& e) {
            return Status(ErrorCodes::InternalError, e.what());
        }

        return Status::OK();
    }

    bool AuthorizationManager::tryAcquireAuthzUpdateLock(const StringData& why) {
        return _externalState->tryAcquireAuthzUpdateLock(why);
    }

    void AuthorizationManager::releaseAuthzUpdateLock() {
        return _externalState->releaseAuthzUpdateLock();
    }

    namespace {
        BSONObj userAsV2PrivilegeDocument(const User& user) {
            BSONObjBuilder builder;

            const UserName& name = user.getName();
            builder.append(AuthorizationManager::USER_NAME_FIELD_NAME, name.getUser());
            builder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, name.getDB());

            const User::CredentialData& credentials = user.getCredentials();
            if (!credentials.isExternal) {
                BSONObjBuilder credentialsBuilder(builder.subobjStart("credentials"));
                credentialsBuilder.append("MONGODB-CR", credentials.password);
                credentialsBuilder.doneFast();
            }

            BSONArrayBuilder rolesArray(builder.subarrayStart("roles"));
            const User::RoleDataMap& roles = user.getRoles();
            for (User::RoleDataMap::const_iterator it = roles.begin(); it != roles.end(); ++it) {
                const User::RoleData& role = it->second;
                BSONObjBuilder roleBuilder(rolesArray.subobjStart());
                roleBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, role.name.getRole());
                roleBuilder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, role.name.getDB());
                roleBuilder.appendBool("canDelegate", role.canDelegate);
                roleBuilder.appendBool("hasRole", role.hasRole);
                roleBuilder.doneFast();
            }
            rolesArray.doneFast();
            return builder.obj();
        }

        const NamespaceString newusersCollectionNamespace("admin._newusers");
        const NamespaceString backupUsersCollectionNamespace("admin.backup.users");
        const BSONObj versionDocumentQuery = BSON("_id" << 1);

        /**
         * Fetches the admin.system.version document and extracts the currentVersion field's
         * value, supposing it is an integer, and writes it to outVersion.
         */
        Status readAuthzVersion(AuthzManagerExternalState* externalState, int* outVersion) {
            BSONObj versionDoc;
            Status status = externalState->findOne(
                    AuthorizationManager::versionCollectionNamespace,
                    versionDocumentQuery,
                    &versionDoc);
            if (!status.isOK() && ErrorCodes::NoMatchingDocument != status) {
                return status;
            }
            BSONElement currentVersionElement = versionDoc["currentVersion"];
            if (!versionDoc.isEmpty() && !currentVersionElement.isNumber()) {
                return Status(ErrorCodes::TypeMismatch,
                              "Field 'currentVersion' in admin.system.version must be a number.");
            }
            *outVersion = currentVersionElement.numberInt();
            return Status::OK();
        }
    }  // namespace

    Status AuthorizationManager::upgradeAuthCollections() {
        AuthzDocumentsUpdateGuard lkUpgrade(this);
        if (!lkUpgrade.tryLock("Upgrade authorization data")) {
            return Status(ErrorCodes::LockBusy, "Could not lock auth data upgrade process lock.");
        }
        boost::lock_guard<boost::mutex> lkLocal(_lock);
        int durableVersion = 0;
        Status status = readAuthzVersion(_externalState.get(), &durableVersion);
        if (!status.isOK())
            return status;

        if (_version == 2) {
            switch (durableVersion) {
            case 0:
            case 1: {
                const char msg[] = "User data format version in memory and on disk inconsistent; "
                    "please restart this node.";
                error() << msg;
                return Status(ErrorCodes::UserDataInconsistent, msg);
            }
            case 2:
                return Status::OK();
            default:
                return Status(ErrorCodes::BadValue,
                              mongoutils::str::stream() <<
                              "Cannot upgrade admin.system.version to 2 from " <<
                              durableVersion);
            }
        }
        fassert(17113, _version == 1);
        switch (durableVersion) {
        case 0:
        case 1:
            break;
        case 2: {
            const char msg[] = "User data format version in memory and on disk inconsistent; "
                "please restart this node.";
            error() << msg;
            return Status(ErrorCodes::UserDataInconsistent, msg);
        }
        default:
                return Status(ErrorCodes::BadValue,
                              mongoutils::str::stream() <<
                              "Cannot upgrade admin.system.version from 2 to " <<
                              durableVersion);
        }

        BSONObj writeConcern;
        // Upgrade from v1 to v2.
        status = _externalState->copyCollection(usersCollectionNamespace,
                                                backupUsersCollectionNamespace,
                                                writeConcern);
        if (!status.isOK())
            return status;
        status = _externalState->dropCollection(newusersCollectionNamespace, writeConcern);
        if (!status.isOK())
            return status;
        status = _externalState->createIndex(
                newusersCollectionNamespace,
                BSON(USER_NAME_FIELD_NAME << 1 << USER_SOURCE_FIELD_NAME << 1),
                true, // unique
                writeConcern
                );
        if (!status.isOK())
            return status;

        for (unordered_map<UserName, User*>::const_iterator iter = _userCache.begin();
             iter != _userCache.end(); ++iter) {

            // Do not create a user document for the internal user.
            if (iter->second == internalSecurity.user)
                continue;

            status = _externalState->insert(
                    newusersCollectionNamespace, userAsV2PrivilegeDocument(*iter->second),
                    writeConcern);
            if (!status.isOK())
                return status;
        }
        status = _externalState->renameCollection(newusersCollectionNamespace,
                                                  usersCollectionNamespace,
                                                  writeConcern);
        if (!status.isOK())
            return status;
        status = _externalState->updateOne(
                versionCollectionNamespace,
                versionDocumentQuery,
                BSON("$set" << BSON("currentVersion" << 2)),
                true,
                writeConcern);
        if (!status.isOK())
            return status;
        _version = 2;
        return status;
    }

    void AuthorizationManager::logOp(
            const char* op,
            const char* ns,
            const BSONObj& o,
            BSONObj* o2,
            bool* b,
            bool fromMigrateUnused,
            const BSONObj* fullObjUnused) {

        _externalState->logOp(op, ns, o, o2, b, fromMigrateUnused, fullObjUnused);
        if (ns == rolesCollectionNamespace.ns() ||
            ns == adminCommandNamespace.ns() ||
            ns == usersCollectionNamespace.ns()) {
            boost::lock_guard<boost::mutex> lk(_lock);
            if (_getVersion_inlock() == 2) {
                _invalidateUserCache_inlock();
            }
        }
    }

} // namespace mongo

ext: cpp

max_issues_repo_name: alonho/mongo

max_forks_repo_name: alonho/mongo


text:
///////////////////////////////////////////////////////////////////////////////
// statistics::model::wrap::aggregate::model_dataset.hpp                     //
//                                                                           //
//  Copyright 2009 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_MODEL_WRAP_AGGREGATE_MODEL_DATASET_HPP_ER_2009
#define BOOST_STATISTICS_MODEL_WRAP_AGGREGATE_MODEL_DATASET_HPP_ER_2009
#include <boost/statistics/model/wrap/unary/model.hpp>
#include <boost/statistics/model/wrap/aggregate/dataset.hpp>

namespace boost{
namespace statistics{
namespace model{

    template<typename M,typename Rx,typename Ry>
    class model_dataset_ :
        public  model_wrapper<M>,
        public  dataset_<Rx,Ry>
    {
        typedef model_wrapper<M> model_;
        typedef dataset_<Rx,Ry> dataset_;
    public:
        typedef model_dataset_<M,Rx,Ry> model_dataset_type;

        // Construction
        model_dataset_();
        model_dataset_(model_ model,dataset_ dataset);
        model_dataset_(
            model_ model,
            typename dataset_::covariates_wrapper_type covs,
            typename dataset_::responses_wrapper_type resps
        );
        model_dataset_(const model_dataset_&);

    };

    // Implementation //

    template<typename M,typename Rx,typename Ry>
    model_dataset_<M,Rx,Ry>::model_dataset_()
    : model_(),dataset_(){}

    template<typename M,typename Rx,typename Ry>
    model_dataset_<M,Rx,Ry>::model_dataset_(
            model_ model,
            typename dataset_::covariates_wrapper_type covs,
            typename dataset_::responses_wrapper_type resps
    ) : model_( model ), dataset_ (covs,resps) {}

    template<typename M,typename Rx,typename Ry>
    model_dataset_<M,Rx,Ry>::model_dataset_(
        const model_dataset_& that)
    :model_( that ),dataset_( that ) {}

    // Free functions

    template<typename M,typename Rx,typename Ry>
    model_dataset_<M,Rx,Ry>
    make_model_dataset(const M& m,const Rx& rx,const Ry& ry){
        typedef model_dataset_<M,Rx,Ry> result_type;
        return result_type(m,rx,ry);
    }

}// model
}// statistics
}// boost

#endif

ext: hpp


text: #include <boost/msm/back/queue_container_deque.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// Copyright 2017 Rodeo FX.  All rights reserved.

#include "index.h"

#include <boost/algorithm/string.hpp>
#include <boost/range/adaptor/reversed.hpp>

PXR_NAMESPACE_USING_DIRECTIVE

void RendererIndex::insertPrim(
        const SdfPath& parentPath, const SdfPath& objectPath)
{
    {
        // Scope because we have another guard mHierarchyMap.
        // TODO: Maybe concurrent_unordered_set is better?
        FastMutexLock lock(mCachedObjectSetLock);
        mCachedObjectSet.insert(objectPath);
    }

    ObjectMap::accessor it;
    mHierarchyMap.insert(it, parentPath);
    it->second.insert(objectPath);
}

bool RendererIndex::isProcessed(const SdfPath& path) const
{
    FastMutexLock lock(mCachedObjectSetLock);
    return mCachedObjectSet.find(path) != mCachedObjectSet.end();
}

int RendererIndex::getNumNodes(const SdfPath& path)
{
    auto it = mNumNodes.find(path);
    if (it != mNumNodes.end())
    {
        return it->second;
    }
    else
    {
        ObjectMap::const_accessor it;
        if (!mHierarchyMap.find(it, path))
        {
            // Nothing is found.
            return 0;
        }

        int numNodes = it->second.size();
        mNumNodes.emplace(path, numNodes);
        return numNodes;
    }
}

void RendererIndex::insertNumNodes(const SdfPath& path, int numNodes)
{
    mNumNodes.emplace(path, numNodes);
}

bool RendererIndex::isChildrenKnown(const SdfPath& path) const
{
    ObjectMap::const_accessor it;
    return mHierarchyMap.find(it, path);
}

bool RendererIndex::isParentKnown(
    const SdfPath& root,
    const SdfPath& path) const
{
    ObjectMap::const_accessor it;
    if (!mHierarchyMap.find(it, root))
    {
        return false;
    }

    for (SdfPath potentialParent: it->second)
    {
        if (path.HasPrefix(potentialParent))
        {
            return true;
        }
    }

    return false;
}

bool RendererIndex::isAssignmentDone() const
{
    return !mAssignments.empty();
}

bool RendererIndex::hasGlobalMaterials() const
{
    SdfPath root("/");
    SdfPath materials("/materials");

    ObjectMap::const_accessor it;
    return mHierarchyMap.find(it, root) || mHierarchyMap.find(it, materials);
}

const SdfPath* RendererIndex::getPath(
        const SdfPath& parentPath, unsigned int i)const
{
    ObjectMap::const_accessor it;
    if (!mHierarchyMap.find(it, parentPath))
    {
        // Nothing is found.
        return nullptr;
    }

    const ObjectSet& set = it->second;
    if (i >= set.size())
    {
        // Out of range.
        return nullptr;
    }

    return &(*std::next(set.begin(), i));
}

bool RendererIndex::getRenderNodeData(
    const SdfPath& path,
    RenderNodeMap::accessor& accessor)
{
    return mRenderNodeMap.insert(accessor, path);
}

bool RendererIndex::getRenderNodeData(
    const SdfPath& path,
    RenderNodeMap::const_accessor& accessor)
{
    return mRenderNodeMap.find(accessor, path);
}

void RendererIndex::insertExpression(
        const SdfPath& expressionPrimPath,
        const SdfPath& rootPath,
        const std::string& expression,
        const WalterExpression::AssignmentLayers& layers)
{
    // The alembic can be loaded as an object. It means it's not in the root and
    // we need to extend the expressions to the full path because we don't want
    // to apply them to all the objects.
    std::string fullExpression = rootPath.GetText();
    // If the latest symbol is '/', remove it.
    if (fullExpression[fullExpression.size()-1] == '/')
    {
        fullExpression = fullExpression.substr(0, fullExpression.size()-1);
    }

    // RND-555: Demangle the expression to convert special regex characters
    fullExpression += WalterCommon::demangleString(
        WalterCommon::convertRegex(expression));

    // Iterate the layers.
    for (auto& l : layers)
    {
        // "defaultRenderLayer"
        TargetToObjShader& currentLayer = mAssignments[l.first];

        for (auto& t : l.second)
        {
            // "shader"
            const std::string& targetName = t.first;

            // Filling mAssignments.
            auto emplaceResult = currentLayer[targetName].emplace(
                std::piecewise_construct,
                std::forward_as_tuple(fullExpression),
                std::forward_as_tuple(t.second));
            if (!emplaceResult.second)
            {
                // The insertion only takes place if no other element in the
                // container has a key equivalent to the one being emplaced.
                // emplaceResult.second is false if the key already existed.
                // Skip it.
                continue;
            }

            // "/materials/aiStandard1"
            SdfPath& material = emplaceResult.first->second;

            // USD converts relative names to absolute names during composition.
            // Make it relative back.
            if (material.GetParentPath() == expressionPrimPath)
            {
                material = material.MakeRelativePath(expressionPrimPath);
            }

            // Material points to the UsdShadeMaterial. Arnold requires a
            // shader. We need to find the shader and save it.
            auto itT = mMaterials.find(material);
            if (itT == mMaterials.end())
            {
                continue;
            }

            const WalterExpression::AssignmentTargets& matTarget = itT->second;

            auto itS = matTarget.find(targetName);
            if (itS == matTarget.end())
            {
                // A special case because a surface shader in Arnold is just
                // "shader"
                if (targetName != "shader" ||
                    (itS = matTarget.find("surface")) == matTarget.end() )
                {
                    continue;
                }
            }

            material = itS->second;
        }

    }
}

void RendererIndex::insertMaterial(
        const SdfPath& material,
        const std::string& target,
        const SdfPath& shader)
{
    mMaterials[material][target] = shader;
}

void RendererIndex::insertAttribute(
        const SdfPath& iOverridePath,
        const std::string& iAttributeName,
        const RendererAttribute& iAttribute)
{
    mAttributes[iOverridePath].emplace(iAttributeName, iAttribute);
}

SdfPath RendererIndex::getShaderAssignment(
        const std::string& objectName,
        const std::string& layer,
        const std::string& target)const
{
    // Looking for requested render layer
    auto layerIt = mAssignments.find(layer);
    if (layerIt == mAssignments.end())
    {
        return SdfPath();
    }

    // Looking for necessary target.
    auto targetIt = layerIt->second.find(target);
    if (targetIt == layerIt->second.end())
    {
        return SdfPath();
    }

    const ObjectToShader& objectList = targetIt->second;

    const SdfPath* shader =
        WalterCommon::resolveAssignment<SdfPath>(objectName, objectList);

    if (!shader)
    {
        return SdfPath();
    }

    return *shader;
}

const NameToAttribute* RendererIndex::getAttributes(SdfPath iOverridePath) const
{
    auto it = mAttributes.find(iOverridePath);
    if (it == mAttributes.end())
    {
        return nullptr;
    }

    const NameToAttribute& attributes = it->second;
    return &attributes;
}

const NameToAttribute* RendererIndex::getObjectAttribute(
    const std::string& iVirtualObjectName,
    const std::string& iLayer)
{
    assert(!iVirtualObjectName.empty());

    // First, try to find the current object in the cache.
    ObjectAttrs::accessor accessor;
    if (mObjectAttributes.find(accessor, iVirtualObjectName))
    {
        // Found!!!
        return &accessor->second;
    }

    // TODO: It's not clear if `accessor` still locks this scope. It shouldn't.

    // Get the name of the walterOverride.
    SdfPath attributePath =
        getShaderAssignment(iVirtualObjectName, iLayer, "attribute");

    // Get the attributes from the walter override object.
    const NameToAttribute* attributes = getAttributes(attributePath);

    if (attributes)
    {
        // Create a list of attributes and copy everything from Walter Override.
        mObjectAttributes.emplace(
            accessor,
            std::piecewise_construct,
            std::forward_as_tuple(iVirtualObjectName),
            std::forward_as_tuple(*attributes));
    }
    else
    {
        // Create a new empty list of attributes.
        mObjectAttributes.emplace(
            accessor,
            std::piecewise_construct,
            std::forward_as_tuple(iVirtualObjectName),
            std::forward_as_tuple());
    }

    // Merge with the attributes of parent.
    if (iVirtualObjectName != "/")
    {
        // Generate the name of the parent.
        // TODO: We could cache even this.
        std::string parentVirtualName;
        size_t found = iVirtualObjectName.find_last_of('/');
        if (found == 0)
        {
            // Special case if the parent is the root.
            parentVirtualName = "/";
        }
        else if (found != std::string::npos)
        {
            parentVirtualName = iVirtualObjectName.substr(0, found);
        }

        if (!parentVirtualName.empty())
        {
            // Recursively get the attributes of the parent.
            const NameToAttribute* parentAttributes =
                getObjectAttribute(parentVirtualName, iLayer);

            if (parentAttributes)
            {
                // Current attributes should be strong, the parent attributes
                // should be weak.
                // TODO: be careful. map::insert has an undefined behaviour.
                // https://cplusplus.github.io/LWG/issue2844
                // It's necessary to check it on all the new compilers.
                accessor->second.insert(
                    parentAttributes->begin(), parentAttributes->end());
            }
        }
    }

    return &accessor->second;
}

const std::string& RendererIndex::getPrefixPath(
    const std::string& iPrefix) const
{
    static const std::string empty;

    StringMap::const_accessor it;
    if (!mPrefixPathsForProcedurals.find(it, iPrefix))
    {
        return empty;
    }

    return it->second;
}

bool RendererIndex::setPrefixPath(
    const std::string& iPrefix,
    const std::string& iPath)
{
    return mPrefixPathsForProcedurals.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(iPrefix),
        std::forward_as_tuple(iPath));
}

max_stars_repo_name: all-in-one-of/OpenWalter

max_issues_repo_name: all-in-one-of/OpenWalter

max_forks_repo_name: all-in-one-of/OpenWalter


text:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <asio-zmq.hpp>

void s_send(boost::asio::zmq::socket& socket, std::string const& str)
{
    std::vector<boost::asio::zmq::frame> message;
    message.push_back(boost::asio::zmq::frame(str));
    socket.write_message(std::begin(message), std::end(message));
}

void s_dump(boost::asio::zmq::socket& socket)
{
    std::cout << "----------------------------------------\n";
    std::vector<boost::asio::zmq::frame> buffer;
    socket.read_message(std::back_inserter(buffer));
    std::for_each(std::begin(buffer), std::end(buffer), [](boost::asio::zmq::frame const& frame) {
        std::cout << std::to_string(frame) << "\n";
    });
}

int main()
{
    boost::asio::io_service ios;
    boost::asio::zmq::context ctx;

    boost::asio::zmq::socket sink(ios, ctx, ZMQ_ROUTER);
    sink.bind("inproc://example");

    boost::asio::zmq::socket anonymous(ios, ctx, ZMQ_REQ);
    anonymous.connect("inproc://example");

    s_send(anonymous, "ROUTER uses a generated UUID");
    s_dump(sink);

    boost::asio::zmq::socket identified(ios, ctx, ZMQ_REQ);
    std::string id = "PEER2";
    identified.set_option(boost::asio::zmq::socket_option::identity(id.c_str(), id.size()));
    identified.connect("inproc://example");

    s_send(identified, "ROUTER socket uses REQ's socket identity");
    s_dump(sink);

    return 0;
}

max_stars_repo_name: yayj/asio-zmq

max_issues_repo_name: yayj/asio-zmq

max_forks_repo_name: yayj/asio-zmq


text:
/*
 [auto_generated]
 libs/numeric/odeint/test/dummy_steppers.hpp

 [begin_description]
 Dummy steppers for several tests.
 [end_description]

 Copyright 2012 Karsten Ahnert
 Copyright 2012 Mario Mulansky

 Distributed under the Boost Software License, Version 1.0.
 (See accompanying file LICENSE_1_0.txt or
 copy at http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_LIBS_NUMERIC_ODEINT_TEST_DUMMY_STEPPER_HPP_INCLUDED
#define BOOST_LIBS_NUMERIC_ODEINT_TEST_DUMMY_STEPPER_HPP_INCLUDED

#include <boost/array.hpp>
#include <boost/numeric/odeint/stepper/stepper_categories.hpp>
#include <boost/numeric/odeint/stepper/controlled_step_result.hpp>

namespace boost {
namespace numeric {
namespace odeint {

struct dummy_stepper
{
    typedef double value_type;
    typedef value_type time_type;
    typedef boost::array< value_type , 1 > state_type;
    typedef state_type deriv_type;
    typedef unsigned short order_type;
    typedef stepper_tag stepper_category;

    order_type order( void ) const { return 1; }

    template< class System >
    void do_step( System sys , state_type &x , time_type t , time_type dt ) const
    {
        x[0] += 0.25;
    }
};

struct dummy_dense_output_stepper
{
    typedef double value_type;
    typedef value_type time_type;
    typedef boost::array< value_type , 1 > state_type;
    typedef state_type deriv_type;
    typedef dense_output_stepper_tag stepper_category;

    void initialize( const state_type &x0 , time_type t0 , time_type dt0 )
    {
        m_x = x0;
        m_t = t0;
        m_dt = dt0;
    }

    template< class System >
    std::pair< time_type , time_type > do_step( System sys )
    {
        m_x[0] += 0.25;
        m_t += m_dt;
        return std::make_pair( m_t - m_dt , m_t );
    }

    void calc_state( time_type t_inter , state_type &x ) const
    {
        value_type theta = ( m_t - t_inter ) / m_dt;
        x[0] = m_x[0] - 0.25 * theta;

    }

    const time_type& current_time( void ) const
    {
        return m_t;
    }

    const state_type& current_state( void ) const
    {
        return m_x;
    }

    const time_type& current_time_step( void ) const
    {
        return m_dt;
    }

    state_type m_x;
    time_type m_t;
    time_type m_dt;
};

struct dummy_controlled_stepper
{
    typedef double value_type;
    typedef value_type time_type;
    typedef boost::array< value_type , 1 > state_type;
    typedef state_type deriv_type;
    typedef controlled_stepper_tag stepper_category;

    template< class Sys >
    controlled_step_result try_step( Sys sys , state_type &x , time_type &t , time_type &dt ) const
    {
        x[0] += 0.25;
        t += dt;
        return success;
    }
};

} // odeint
} // numeric
} // boost

#endif // BOOST_LIBS_NUMERIC_ODEINT_TEST_DUMMY_STEPPER_HPP_INCLUDED


text:
#include <boost/test/unit_test.hpp>

#include <chainparams.h>
#include <net_processing.h>
#include <validation.h>
#include <wallet/wallet.h>
#include <test/util/setup_common.h>

#include <vbk/test/util/mock.hpp>
#include <vbk/test/util/tx.hpp>

struct NetServiceFixture : public TestingSetup {
    VeriBlockTest::ServicesFixture service_fixture;
};

static CService ip(uint32_t i)
{
    struct in_addr s;
    s.s_addr = i;
    return CService(CNetAddr(s), Params().GetDefaultPort());
}

BOOST_FIXTURE_TEST_SUITE(vbk_net_processing, NetServiceFixture)

BOOST_AUTO_TEST_CASE(SendMessages_with_pop_tx)
{
    CMutableTransaction popTx1 = VeriBlockTest::makePopTx({ 1 }, { std::vector<uint8_t>(100, 1) });
    CMutableTransaction popTx2 = VeriBlockTest::makePopTx({ 2 }, { std::vector<uint8_t>(100, 2) });
    CMutableTransaction popTx3 = VeriBlockTest::makePopTx({ 3 }, { std::vector<uint8_t>(100, 3) });

    auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
    auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler);

    // Mock an outbound peer
    CAddress addr1(ip(0xa0b0c001), NODE_NONE);
    CNode dummyNode1(0, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false);
    dummyNode1.SetSendVersion(PROTOCOL_VERSION);

    peerLogic->InitializeNode(&dummyNode1);
    {
        LOCK2(dummyNode1.m_tx_relay->cs_tx_inventory, dummyNode1.m_tx_relay->cs_feeFilter);
        dummyNode1.nVersion = 1;
        dummyNode1.fSuccessfullyConnected = true;
        dummyNode1.m_tx_relay->fSendMempool = true;
        dummyNode1.m_tx_relay->minFeeFilter = 1000;
    }

    {
        LOCK2(cs_main, dummyNode1.cs_sendProcessing);
        BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
    }
    {
        LOCK2(cs_main, dummyNode1.m_tx_relay->cs_tx_inventory);
        BOOST_CHECK(!dummyNode1.m_tx_relay->filterInventoryKnown.contains(popTx1.GetHash()));
        BOOST_CHECK(!dummyNode1.m_tx_relay->filterInventoryKnown.contains(popTx2.GetHash()));
        BOOST_CHECK(!dummyNode1.m_tx_relay->filterInventoryKnown.contains(popTx3.GetHash()));
    }

    {
        TestMemPoolEntryHelper entry;
        LOCK2(cs_main, mempool.cs);
        TxValidationState state;
        BOOST_CHECK(AcceptToMemoryPool(mempool, state, MakeTransactionRef(popTx1), nullptr, false, DEFAULT_TRANSACTION_MAXFEE));
        BOOST_CHECK(AcceptToMemoryPool(mempool, state, MakeTransactionRef(popTx2), nullptr, false, DEFAULT_TRANSACTION_MAXFEE));
        BOOST_CHECK(AcceptToMemoryPool(mempool, state, MakeTransactionRef(popTx3), nullptr, false, DEFAULT_TRANSACTION_MAXFEE));
    }

    CNode dummyNode2(0, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false);
    dummyNode2.SetSendVersion(PROTOCOL_VERSION);

    peerLogic->InitializeNode(&dummyNode2);
    {
        LOCK2(dummyNode2.m_tx_relay->cs_tx_inventory, dummyNode2.m_tx_relay->cs_feeFilter);
        dummyNode2.nVersion = 1;
        dummyNode2.fSuccessfullyConnected = true;
        dummyNode2.m_tx_relay->fSendMempool = true;
        dummyNode2.m_tx_relay->minFeeFilter = 1000;
    }

    {
        LOCK2(cs_main, dummyNode2.cs_sendProcessing);
        BOOST_CHECK(peerLogic->SendMessages(&dummyNode2)); // should result in getheaders
    }
    {
        LOCK2(cs_main, dummyNode2.m_tx_relay->cs_tx_inventory);
        BOOST_CHECK(dummyNode2.m_tx_relay->filterInventoryKnown.contains(popTx1.GetHash()));
        BOOST_CHECK(dummyNode2.m_tx_relay->filterInventoryKnown.contains(popTx2.GetHash()));
        BOOST_CHECK(dummyNode2.m_tx_relay->filterInventoryKnown.contains(popTx3.GetHash()));
    }
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: xagau/vbk-ri-btc

max_issues_repo_name: xagau/vbk-ri-btc

max_forks_repo_name: xagau/vbk-ri-btc