<commit_before>
#include <limits>
#include <cassert>
#include <type_traits>

//
// CppCon 2014: Walter E. Brown "Modern Template Metaprogramming: A Compendium"
//
//   ~ https://www.youtube.com/watch?v=Am2is2QCvxY
//   ~ https://www.youtube.com/watch?v=a0FliKwcwXE
//

namespace meta
{
	template <int N>
	struct Abs
	{
		static_assert(N != std::numeric_limits<int>::max(), "Out of range!");

		static constexpr auto value = (N > 0) ? N : -N;
	};

	constexpr int abs(const int n)
	{
		assert(n != std::numeric_limits<int>::max());

		return (n > 0) ? n : -n;
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <int Base, int Exponent>
	struct Power
	{
		static_assert(Exponent >= 0, "Fractions are not allowed!");

		static constexpr auto value = Power<Base, Exponent - 1>::value * Base;
	};

	template <int Base>
	struct Power <Base, 1>
	{
		static constexpr auto value = Base;
	};

	template <int Base>
	struct Power <Base, 0>
	{
		static_assert(Base != 0, "Indeterminate form are not allowed!");

		static constexpr auto value = 1;
	};

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, Type Constant>
	struct integral_constant
	{
		static constexpr auto value = Constant;
	};

	template <bool Boolean>
	using bool_constant = integral_constant <bool, Boolean>;

	using  true_type = bool_constant < true>;
	using false_type = bool_constant <false>;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct identity
	{
		using type = Type;
	};

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct remove_const : identity<Type> { };

	template <typename Type>
	struct remove_const <const Type> : identity<Type> { };

	template <typename Type>
	using remove_const_t = typename remove_const<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct remove_volatile : identity<Type> { };

	template <typename Type>
	struct remove_volatile <volatile Type> : identity<Type> { };

	template <typename Type>
	using remove_volatile_t = typename remove_volatile<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	using remove_cv = remove_volatile<typename remove_const<Type>::type>;

	template <typename Type>
	using remove_cv_t = typename remove_cv<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <bool Condition, typename ThenType, typename ElseType>
	struct conditional;

	template <typename ThenType, typename ElseType>
	struct conditional<true, ThenType, ElseType> : identity<ThenType> { };

	template <typename ThenType, typename ElseType>
	struct conditional<false, ThenType, ElseType> : identity<ElseType> { };

	template <bool Condition, typename ThenType, typename ElseType>
	using conditional_t = typename conditional<Condition, ThenType, ElseType>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <bool Condition, typename Type>
	struct enable_if;

	template <typename Type>
	struct enable_if <true, Type> : identity<Type> { };

	template <typename Type>
	struct enable_if <false, Type> { };

	template <bool Condition, typename Type>
	using enable_if_t = typename enable_if<Condition, Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	/* * * * * * * * * * * * * * * * * * * * * * * * * *
	 * SFINAE --> Substitution Failure Is Not An Error *
	 * * * * * * * * * * * * * * * * * * * * * * * * * */

	template <typename T>
	enable_if_t<std::is_integral<T>::value, char> foo (const T)
	{
		return 'i'; // overload for integral types
	}

	template <typename T>
	enable_if_t<std::is_floating_point<T>::value, char> foo (const T)
	{
		return 'f'; // overload for floating point types
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename FirstType, typename SecondType>
	struct is_same : false_type { };

	template <typename Type>
	struct is_same <Type, Type> : true_type { };

	template <typename FirstType, typename SecondType>
	constexpr auto is_same_v = is_same<FirstType, SecondType>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	using is_void = is_same<typename remove_cv<Type>::type, void>;

	template <typename Type>
	constexpr auto is_void_v = is_void<Type>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename ...>
	using void_t = void;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, typename = void>
	struct has_type_member : false_type { };

	template <typename Type>
	struct has_type_member <Type, void_t<typename Type::type>> : true_type { };

	template <typename Type>
	constexpr auto has_type_member_v = has_type_member<Type>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, typename = void>
	struct has_value_member : false_type { };

	template <typename Type>
	struct has_value_member <Type, void_t<decltype(Type::value)>> : true_type { };

	template <typename Type>
	constexpr auto has_value_member_v = has_value_member<Type>::value;
}

namespace assert
{
	template <typename FirstType, typename SecondType>
	struct same_types
	{
		static_assert
		(
			std::is_same<FirstType, SecondType>::value,
			"Types have to be the same!"
		);
	};

	template <auto FirstValue, auto SecondValue>
	struct equal_values
	{
		static_assert
		(
			FirstValue == SecondValue,
			"Values have to be the equal!"
		);
	};
}

namespace
{
	struct Foo
	{
		using type = Foo;
	};

	struct Bar
	{
		static constexpr auto value = Foo { };
	};
}

int main()
{
	assert::equal_values<meta::Abs<-9>::value, 9>();
	assert::equal_values<meta::Abs<+7>::value, 7>();

	assert::equal_values<meta::abs(-9), 9>();
	assert::equal_values<meta::abs(+7), 7>();

	assert::equal_values<meta::Power< 2, 8>::value, 256>();
	assert::equal_values<meta::Power<-5, 3>::value,-125>();
	assert::equal_values<meta::Power< 0, 3>::value,   0>();
	assert::equal_values<meta::Power< 3, 0>::value,   1>();
	assert::equal_values<meta::Power<11, 1>::value,  11>();

	assert::equal_values<meta::integral_constant<int, 7>::value, 7>();
	assert::same_types<decltype(meta::integral_constant<char, '$'>::value), const char>();

	assert::same_types<meta::remove_const_t<const    int>,          int>();
	assert::same_types<meta::remove_const_t<volatile int>, volatile int>();

	assert::same_types<meta::remove_volatile_t<volatile int>,       int>();
	assert::same_types<meta::remove_volatile_t<const    int>, const int>();

	assert::same_types<meta::remove_cv_t<               int>,       int>();
	assert::same_types<meta::remove_cv_t<      volatile int>,       int>();
	assert::same_types<meta::remove_cv_t<const          int>,       int>();
	assert::same_types<meta::remove_cv_t<const volatile int>,       int>();

	assert::same_types<meta::conditional_t< true, char, long>, char>();
	assert::same_types<meta::conditional_t<false, char, long>, long>();

	assert::same_types<meta::enable_if_t<true, char>, char>();
	assert(meta::foo(5)   == 'i');
	assert(meta::foo(5.0) == 'f');

	assert::equal_values<meta::is_same_v<char, char>,  true>();
	assert::equal_values<meta::is_same_v<char, long>, false>();

	assert::equal_values<meta::is_void_v<               void>,  true>();
	assert::equal_values<meta::is_void_v<const          void>,  true>();
	assert::equal_values<meta::is_void_v<      volatile void>,  true>();
	assert::equal_values<meta::is_void_v<const volatile void>,  true>();
	assert::equal_values<meta::is_void_v<               long>, false>();

	assert::equal_values<meta::has_type_member_v<Foo>,  true>();
	assert::equal_values<meta::has_type_member_v<Bar>, false>();

	assert::equal_values<meta::has_value_member_v<Bar>,  true>();
	assert::equal_values<meta::has_value_member_v<Foo>, false>();

	return 0;
}
<commit_msg>Metaprogramming -> Added constexpr to both foo() overloads.<commit_after>
#include <limits>
#include <cassert>
#include <type_traits>

//
// CppCon 2014: Walter E. Brown "Modern Template Metaprogramming: A Compendium"
//
//   ~ https://www.youtube.com/watch?v=Am2is2QCvxY
//   ~ https://www.youtube.com/watch?v=a0FliKwcwXE
//

namespace meta
{
	template <int N>
	struct Abs
	{
		static_assert(N != std::numeric_limits<int>::max(), "Out of range!");

		static constexpr auto value = (N > 0) ? N : -N;
	};

	constexpr int abs(const int n)
	{
		assert(n != std::numeric_limits<int>::max());

		return (n > 0) ? n : -n;
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <int Base, int Exponent>
	struct Power
	{
		static_assert(Exponent >= 0, "Fractions are not allowed!");

		static constexpr auto value = Power<Base, Exponent - 1>::value * Base;
	};

	template <int Base>
	struct Power <Base, 1>
	{
		static constexpr auto value = Base;
	};

	template <int Base>
	struct Power <Base, 0>
	{
		static_assert(Base != 0, "Indeterminate form are not allowed!");

		static constexpr auto value = 1;
	};

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, Type Constant>
	struct integral_constant
	{
		static constexpr auto value = Constant;
	};

	template <bool Boolean>
	using bool_constant = integral_constant <bool, Boolean>;

	using  true_type = bool_constant < true>;
	using false_type = bool_constant <false>;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct identity
	{
		using type = Type;
	};

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct remove_const : identity<Type> { };

	template <typename Type>
	struct remove_const <const Type> : identity<Type> { };

	template <typename Type>
	using remove_const_t = typename remove_const<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	struct remove_volatile : identity<Type> { };

	template <typename Type>
	struct remove_volatile <volatile Type> : identity<Type> { };

	template <typename Type>
	using remove_volatile_t = typename remove_volatile<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	using remove_cv = remove_volatile<typename remove_const<Type>::type>;

	template <typename Type>
	using remove_cv_t = typename remove_cv<Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <bool Condition, typename ThenType, typename ElseType>
	struct conditional;

	template <typename ThenType, typename ElseType>
	struct conditional<true, ThenType, ElseType> : identity<ThenType> { };

	template <typename ThenType, typename ElseType>
	struct conditional<false, ThenType, ElseType> : identity<ElseType> { };

	template <bool Condition, typename ThenType, typename ElseType>
	using conditional_t = typename conditional<Condition, ThenType, ElseType>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <bool Condition, typename Type>
	struct enable_if;

	template <typename Type>
	struct enable_if <true, Type> : identity<Type> { };

	template <typename Type>
	struct enable_if <false, Type> { };

	template <bool Condition, typename Type>
	using enable_if_t = typename enable_if<Condition, Type>::type;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	/* * * * * * * * * * * * * * * * * * * * * * * * * *
	 * SFINAE --> Substitution Failure Is Not An Error *
	 * * * * * * * * * * * * * * * * * * * * * * * * * */

	template <typename T>
	constexpr enable_if_t<std::is_integral<T>::value, char> foo (const T)
	{
		return 'i'; // overload for integral types
	}

	template <typename T>
	constexpr enable_if_t<std::is_floating_point<T>::value, char> foo (const T)
	{
		return 'f'; // overload for floating point types
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename FirstType, typename SecondType>
	struct is_same : false_type { };

	template <typename Type>
	struct is_same <Type, Type> : true_type { };

	template <typename FirstType, typename SecondType>
	constexpr auto is_same_v = is_same<FirstType, SecondType>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type>
	using is_void = is_same<typename remove_cv<Type>::type, void>;

	template <typename Type>
	constexpr auto is_void_v = is_void<Type>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename ...>
	using void_t = void;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, typename = void>
	struct has_type_member : false_type { };

	template <typename Type>
	struct has_type_member <Type, void_t<typename Type::type>> : true_type { };

	template <typename Type>
	constexpr auto has_type_member_v = has_type_member<Type>::value;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //

	template <typename Type, typename = void>
	struct has_value_member : false_type { };

	template <typename Type>
	struct has_value_member <Type, void_t<decltype(Type::value)>> : true_type { };

	template <typename Type>
	constexpr auto has_value_member_v = has_value_member<Type>::value;
}

namespace assert
{
	template <typename FirstType, typename SecondType>
	struct same_types
	{
		static_assert
		(
			std::is_same<FirstType, SecondType>::value,
			"Types have to be the same!"
		);
	};

	template <auto FirstValue, auto SecondValue>
	struct equal_values
	{
		static_assert
		(
			FirstValue == SecondValue,
			"Values have to be the equal!"
		);
	};
}

namespace
{
	struct Foo
	{
		using type = Foo;
	};

	struct Bar
	{
		static constexpr auto value = Foo { };
	};
}

int main()
{
	assert::equal_values<meta::Abs<-9>::value, 9>();
	assert::equal_values<meta::Abs<+7>::value, 7>();

	assert::equal_values<meta::abs(-9), 9>();
	assert::equal_values<meta::abs(+7), 7>();

	assert::equal_values<meta::Power< 2, 8>::value, 256>();
	assert::equal_values<meta::Power<-5, 3>::value,-125>();
	assert::equal_values<meta::Power< 0, 3>::value,   0>();
	assert::equal_values<meta::Power< 3, 0>::value,   1>();
	assert::equal_values<meta::Power<11, 1>::value,  11>();

	assert::equal_values<meta::integral_constant<int, 7>::value, 7>();
	assert::same_types<decltype(meta::integral_constant<char, '$'>::value), const char>();

	assert::same_types<meta::remove_const_t<const    int>,          int>();
	assert::same_types<meta::remove_const_t<volatile int>, volatile int>();

	assert::same_types<meta::remove_volatile_t<volatile int>,       int>();
	assert::same_types<meta::remove_volatile_t<const    int>, const int>();

	assert::same_types<meta::remove_cv_t<               int>,       int>();
	assert::same_types<meta::remove_cv_t<      volatile int>,       int>();
	assert::same_types<meta::remove_cv_t<const          int>,       int>();
	assert::same_types<meta::remove_cv_t<const volatile int>,       int>();

	assert::same_types<meta::conditional_t< true, char, long>, char>();
	assert::same_types<meta::conditional_t<false, char, long>, long>();

	assert::same_types<meta::enable_if_t<true, char>, char>();
	assert::equal_values<meta::foo(5  ), 'i'>();
	assert::equal_values<meta::foo(5.0), 'f'>();

	assert::equal_values<meta::is_same_v<char, char>,  true>();
	assert::equal_values<meta::is_same_v<char, long>, false>();

	assert::equal_values<meta::is_void_v<               void>,  true>();
	assert::equal_values<meta::is_void_v<const          void>,  true>();
	assert::equal_values<meta::is_void_v<      volatile void>,  true>();
	assert::equal_values<meta::is_void_v<const volatile void>,  true>();
	assert::equal_values<meta::is_void_v<               long>, false>();

	assert::equal_values<meta::has_type_member_v<Foo>,  true>();
	assert::equal_values<meta::has_type_member_v<Bar>, false>();

	assert::equal_values<meta::has_value_member_v<Bar>,  true>();
	assert::equal_values<meta::has_value_member_v<Foo>, false>();

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <ctime>
#include <functional>

#include <nix/valid/validator.hpp>
#include <nix/valid/checks.hpp>
#include <nix/valid/conditions.hpp>
#include <nix/valid/validate.hpp>

#include <nix.hpp>

#include "TestValidate.hpp"

using namespace nix;
using namespace valid;
using namespace std;

void TestValidate::setUp() {
    startup_time = time(NULL);
}

void TestValidate::tearDown() {
    return;
}

void TestValidate::test() {
    // dummy class to test empty checks
    class fooC {
    public:
        std::string getFoo () const { return std::string("I'm not empty!"); };
        std::string getBar () const { return std::string(); };
    };

    std::vector<std::string> vect = {"foo", "bar"};
    std::vector<std::string> vect2;
    fooC foobar;

    // NOTE: we can't test nix specific checks since nix & validation
    // structs cannot be included together
    valid::Result myResult = validator({
        could(vect, &std::vector<std::string>::empty, notFalse(), {
            must(vect, &std::vector<std::string>::size, notSmaller(2), "some msg") }),
        must(vect, &std::vector<std::string>::size, notSmaller(2), "some msg"),
        must(vect, &std::vector<std::string>::size, isSmaller(2), "some msg"),
        should(vect, &std::vector<std::string>::size, notGreater(2), "some msg"),
        should(vect, &std::vector<std::string>::size, isGreater(0), "some msg"),
        must(vect, &std::vector<std::string>::size, notEqual<size_t>(0), "some msg"),
        should(vect, &std::vector<std::string>::size, isEqual<size_t>(2), "some msg"),
        must(vect2, &std::vector<std::string>::size, isFalse(), "some msg"),
        must(foobar, &fooC::getFoo, notEmpty(), "some msg"),
        should(foobar, &fooC::getBar, isEmpty(), "some msg")
    });

    CPPUNIT_ASSERT(myResult.hasWarnings() == false);
    CPPUNIT_ASSERT(myResult.hasErrors() == false);
}
<commit_msg>Small fixes to TestValidate<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <ctime>
#include <functional>

#include <nix/valid/validator.hpp>
#include <nix/valid/checks.hpp>
#include <nix/valid/conditions.hpp>
#include <nix/valid/validate.hpp>

#include <nix.hpp>

#include "TestValidate.hpp"

using namespace nix;
using namespace valid;
using namespace std;

void TestValidate::setUp() {
    startup_time = time(NULL);
}

void TestValidate::tearDown() {
    return;
}

void TestValidate::test() {
    // dummy class to test empty checks
    class fooC {
    public:
        std::string getFoo () const { return std::string("I'm not empty!"); };
        std::string getBar () const { return std::string(); };
    };

    std::vector<std::string> vect = {"foo", "bar"};
    std::vector<std::string> vect2;
    fooC foobar;

    // NOTE: we can't test nix specific checks since nix & validation
    // structs cannot be included together
    valid::Result myResult = validator({
        could(vect, &std::vector<std::string>::empty, isFalse(), {
            must(vect, &std::vector<std::string>::size, notSmaller(2), "notSmaller(2)") }),
        must(vect, &std::vector<std::string>::size, notSmaller(2), "notSmaller(2)"),
        must(vect2, &std::vector<std::string>::size, isSmaller(2), "isSmaller(2)"),
        should(vect, &std::vector<std::string>::size, notGreater(2), "notGreater(2)"),
        should(vect, &std::vector<std::string>::size, isGreater(0), "isGreater(0)"),
        must(vect, &std::vector<std::string>::size, notEqual<size_t>(0), "notEqual<size_t>(0)"),
        should(vect, &std::vector<std::string>::size, isEqual<size_t>(2), "isEqual<size_t>(2)"),
        must(vect2, &std::vector<std::string>::size, isFalse(), "isFalse()"),
        must(foobar, &fooC::getFoo, notEmpty(), "notEmpty()"),
        should(foobar, &fooC::getBar, isEmpty(), "isEmpty()")
    });
    // uncomment this to have debug info
    // std::cout << myResult;

    CPPUNIT_ASSERT(myResult.hasWarnings() == false);
    CPPUNIT_ASSERT(myResult.hasErrors() == false);
}
<|endoftext|>


<commit_before>#include <mlopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <memory>
#include <utility>
#include <iostream>
#include <cmath>
#include <mlopen/tensor.hpp>
#include <mlopen/convolution.hpp>
#include <mlopen/returns.hpp>
#include <mlopen/each_args.hpp>
#include <limits>
#include <thread>

#include "network_data.hpp"

template<class F>
struct protect_fn
{
    F f;
    protect_fn(F x) : f(std::move(x))
    {}

    template<class... Ts>
    auto operator()(Ts&&... xs) const MLOPEN_RETURNS
    (f(std::forward<Ts>(xs)...));
};

template<class F>
protect_fn<F> protect(F f)
{
    return {std::move(f)};
}

template<class F>
void par_for(int n, F f)
{
    const auto threadsize = std::thread::hardware_concurrency();
    if (n < threadsize)
    {
        for(int i=0;i<n;i++) f(i);
    }
    else
    {
        std::vector<std::thread> threads(threadsize);
        const int grainsize = n / threads.size();

        int work = 0;
        std::generate(threads.begin(), threads.end(), [&]
        {
            int start = work;
            int last = std::min(n, work+grainsize);
            // std::cout << "work, last: " << work << ", " << last << std::endl;
            assert((last - start) <= grainsize);
            assert((last - start) > 0);
            auto result = std::thread([&f, start, last]
            {
                for(int i=start;i<last;i++)
                {
                    f(i);
                }
            });
            work += grainsize;
            return result;
        });
        // TODO: Should be in destructor
        for(auto&& t:threads)
        {
            if (t.joinable()) t.join();
        }
    }
}

// Multidimensional for loop
struct ford_impl
{
    template<class F, class T>
    void operator()(F f, T x) const
    {
        for(T i=0;i<x;i++) f(i);
    }

    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9)
        // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914
        // This reverses the order of evaluation
        (*this)([&](Ts... is)
        {
            (*this)(std::bind(protect(f), std::placeholders::_1, is...), x);
        }, xs...);
#else
        (*this)([&](T i)
        {
            (*this)([&](Ts... is)
            {
                f(i, is...);
            }, xs...);
        }, x);
#endif

    }
};

template<class... Ts>
auto ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(ford_impl{}, std::placeholders::_1, xs...)
);

struct par_ford_impl
{
    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9)
        // No parallelism for gcc 4.8
        ford(x, xs...)(f);
#else
        par_for(x, [&](T i)
        {
            ford(xs...)([&](Ts... is)
            {
                f(i, is...);
            });
        });
#endif
    }
};

template<class... Ts>
auto par_ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(par_ford_impl{}, std::placeholders::_1, xs...)
);

template<class T>
struct tensor
{
    mlopen::TensorDescriptor desc;
    std::vector<T> data;

    tensor(int n, int c, int h, int w)
    : desc(mlopenFloat, {n,c,h,w}), data(n*c*h*w)
    {}

    tensor(mlopen::TensorDescriptor rhs)
    : desc(std::move(rhs))
    {
        data.resize(desc.GetElementSize());
    }

    template<class G>
    tensor& generate(G g) &
    {
        this->generate_impl(g);
        return *this;
    }

    template<class G>
    tensor&& generate(G g) &&
    {
        this->generate_impl(g);
        return std::move(*this);
    }

    template<class G>
    void generate_impl(G g)
    {
        auto iterator = data.begin();
        this->for_each([&](int i, int j, int k, int m)
        {
            assert(iterator < data.end());
            *iterator = g(i, j, k, m);
            ++iterator;
        });
    }

    template<class F>
    void for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        ford(n, c, h, w)(std::move(f));
    }

    template<class F>
    void par_for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        par_ford(n, c, h, w)(std::move(f));
    }

    T& operator()(int n, int c, int h, int w)
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }

    const T& operator()(int n, int c, int h, int w) const
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }
};

struct tensor_generate
{
    template<class Tensor, class G>
    Tensor&& operator()(Tensor&& t, G g) const
    {
        return std::forward<Tensor>(t.generate(g));
    }
};

template<class T>
tensor<T> get_output_tensor(const mlopen::ConvolutionDescriptor& filter, const tensor<T>& input, const tensor<T>& weights)
{
    return tensor<T>{filter.GetForwardOutputTensor(input.desc, weights.desc)};
}

template<class T>
std::vector<T> forward_conv(const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    int in_n, in_c, in_h, in_w;
    std::tie(in_n, in_c, in_h, in_w) = mlopen::tie4(input.desc.GetLengths());

    int wei_h, wei_w;
    std::tie(std::ignore, std::ignore, wei_h, wei_w) = mlopen::tie4(weights.desc.GetLengths());

    out.par_for_each([&](int o, int w, int i, int j)
    {
        int in_off_h = i * filter.v;
        int in_off_w = j * filter.u;

        T acc = bias;
        for(int k = 0; k < in_c; k++) { // in_channels (RGB)
            for(int x = 0; x < wei_h; x++) {
                int in_x = in_off_h - filter.pad_h + x;
                if(in_x >= 0 && in_x < in_h) {
                    for(int y = 0; y < wei_w; y++) {
                        int in_y = in_off_w - filter.pad_w + y;
                        if(in_y >= 0 && in_y < in_w) {
                            acc += input(o, k, in_x, in_y) * weights(w, k, x, y);
                        }
                    }
                }
            }
        }
        out(o, w, i, j) = acc;
    });
    return out.data;
}

template<class T>
std::vector<T> forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int /* bias */ = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    auto in_dev = handle.Write(input.data);
    auto wei_dev = handle.Write(weights.data);
    auto out_dev = handle.Create<T>(out.data.size());

    int ret_algo_count;
    mlopenConvAlgoPerf_t perf;

    int alpha = 1, beta = 1;

    filter.FindConvFwdAlgorithm(handle,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        out.desc,
        out_dev.get(),
        1,
        &ret_algo_count,
        &perf,
        mlopenConvolutionFastest,
        NULL,
        10,
        0); // MD: Not performing exhaustiveSearch by default for now

    filter.ConvolutionForward(handle,
        &alpha,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        mlopenConvolutionFwdAlgoDirect,
        &beta,
        out.desc,
        out_dev.get(),
        NULL,
        0);

    out.data = handle.Read<T>(out_dev, out.data.size());
    return out.data;
}

struct float_equal_fn
{
    template<class T>
    bool operator()(T x, T y) const
    {
        return std::fabs(x - y) < std::max(std::numeric_limits<T>::epsilon() * std::max(x, y), std::numeric_limits<T>::epsilon());
    }
};

template<class R1, class R2>
bool float_equal_range(R1&& r1, R2&& r2)
{
    return std::distance(r1.begin(), r1.end()) == std::distance(r2.begin(), r2.end()) &&
        std::equal(r1.begin(), r1.end(), r2.begin(), float_equal_fn{});
}

template<class R1, class R2, class Op>
float accumulate_difference(R1&& r1, R2&& r2, Op op)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), 0.0, op,
        [](float x, float y) { return std::fabs(x - y); }
    );
}

template<class T>
void verify_forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out_cpu = forward_conv(input, weights, filter, bias);
    auto out_gpu = forward_conv(handle, input, weights, filter, bias);
    int size = std::distance(out_cpu.begin(), out_cpu.end());
    CHECK(std::distance(out_cpu.begin(), out_cpu.end()) == std::distance(out_gpu.begin(), out_gpu.end()));
    if (!float_equal_range(out_cpu, out_gpu))
    {
        std::cout << "FAILED: " << std::endl;
        std::cout
            << "Average difference: "
            << (accumulate_difference(out_cpu, out_gpu, std::plus<float>()) / size)
            << std::endl;
        std::cout
            << "Max difference: "
            << (accumulate_difference(out_cpu, out_gpu, [](float x, float y) { return std::max(x, y); }))
            << std::endl;
    }
    // CHECK(out_cpu == out_gpu);
}

struct cross_args_apply
{
    template<class F, class T, class... Ts>
    void operator()(F f, T&& x, Ts&&... xs) const
    {
        mlopen::each_args(std::bind(f, std::forward<T>(x), std::placeholders::_1), std::forward<Ts>(xs)...);
    }
};

template<class F, class... Ts>
void cross_args(F f, Ts&&... xs)
{
    mlopen::each_args(
        std::bind(cross_args_apply{}, protect(std::move(f)), std::placeholders::_1, std::forward<Ts>(xs)...),
    std::forward<Ts>(xs)...);
}

template<class T>
struct verify_both
{
    template<class G1, class G2>
    void operator()(mlopen::Handle& handle, G1 g1, G2 g2) const
    {
        visit_network<T>([&](mlopen::TensorDescriptor input_desc, mlopen::TensorDescriptor weights_desc)
        {
            auto input = tensor<T>{std::move(input_desc)}.generate(g1);
            auto weights = tensor<T>{std::move(weights_desc)}.generate(g2);
            mlopen::ConvolutionDescriptor filter{1, 1};

            std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
            std::cout << "Weights tensor: " << weights.desc.ToString() << std::endl;

            verify_forward_conv(handle, input, weights, filter);
        });
    }
};

template<class T, class... Gs>
void verify_all(mlopen::Handle& handle, Gs... gs)
{
    cross_args(
        std::bind(verify_both<T>{}, std::ref(handle), std::placeholders::_1, std::placeholders::_2),
        gs...);
}

template<class T, class G>
void verify_one(mlopen::Handle& handle, G g)
{
    auto input = tensor<T>{16, 32, 8, 8}.generate(g);
    auto weights = tensor<T>{64, 32, 5, 5}.generate(g);
    mlopen::ConvolutionDescriptor filter{1, 1};
    verify_forward_conv(handle, input, weights, filter);
}

int main() {
    mlopen::Handle handle;
    auto g0 = [](int, int, int, int) { return 0; };
    auto g1 = [](int, int, int, int) { return 1; };
    auto g_id = [](int, int, int h, int w) { return h == w ? 1 : 0; };
    auto g = [](int n, int c, int h, int w)
    {
        double x = (547*n+701*c+877*h+1049*w+173)%1223;
        return x/691.0;
    };
    (void)g0;
    (void)g1;
    (void)g_id;
    (void)g;
#if MLOPEN_TEST_ALL
    printf("verify_all\n");
    verify_all<float>(handle, g0,g1, g_id, g);
#else
    printf("verify_one\n");
    verify_one<float>(handle, g);
#endif
}
<commit_msg>Simplify forwarding<commit_after>#include <mlopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <memory>
#include <utility>
#include <iostream>
#include <cmath>
#include <mlopen/tensor.hpp>
#include <mlopen/convolution.hpp>
#include <mlopen/returns.hpp>
#include <mlopen/each_args.hpp>
#include <limits>
#include <thread>

#include "network_data.hpp"

template<class F>
struct protect_fn
{
    F f;
    protect_fn(F x) : f(std::move(x))
    {}

    template<class... Ts>
    auto operator()(Ts&&... xs) const MLOPEN_RETURNS
    (f(std::forward<Ts>(xs)...));
};

template<class F>
protect_fn<F> protect(F f)
{
    return {std::move(f)};
}

template<class F>
void par_for(int n, F f)
{
    const auto threadsize = std::thread::hardware_concurrency();
    if (n < threadsize)
    {
        for(int i=0;i<n;i++) f(i);
    }
    else
    {
        std::vector<std::thread> threads(threadsize);
        const int grainsize = n / threads.size();

        int work = 0;
        std::generate(threads.begin(), threads.end(), [&]
        {
            int start = work;
            int last = std::min(n, work+grainsize);
            // std::cout << "work, last: " << work << ", " << last << std::endl;
            assert((last - start) <= grainsize);
            assert((last - start) > 0);
            auto result = std::thread([&f, start, last]
            {
                for(int i=start;i<last;i++)
                {
                    f(i);
                }
            });
            work += grainsize;
            return result;
        });
        // TODO: Should be in destructor
        for(auto&& t:threads)
        {
            if (t.joinable()) t.join();
        }
    }
}

// Multidimensional for loop
struct ford_impl
{
    template<class F, class T>
    void operator()(F f, T x) const
    {
        for(T i=0;i<x;i++) f(i);
    }

    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9)
        // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914
        // This reverses the order of evaluation
        (*this)([&](Ts... is)
        {
            (*this)(std::bind(protect(f), std::placeholders::_1, is...), x);
        }, xs...);
#else
        (*this)([&](T i)
        {
            (*this)([&](Ts... is)
            {
                f(i, is...);
            }, xs...);
        }, x);
#endif

    }
};

template<class... Ts>
auto ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(ford_impl{}, std::placeholders::_1, xs...)
);

struct par_ford_impl
{
    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
#if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9)
        // No parallelism for gcc 4.8
        ford(x, xs...)(f);
#else
        par_for(x, [&](T i)
        {
            ford(xs...)([&](Ts... is)
            {
                f(i, is...);
            });
        });
#endif
    }
};

template<class... Ts>
auto par_ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(par_ford_impl{}, std::placeholders::_1, xs...)
);

template<class T>
struct tensor
{
    mlopen::TensorDescriptor desc;
    std::vector<T> data;

    tensor(int n, int c, int h, int w)
    : desc(mlopenFloat, {n,c,h,w}), data(n*c*h*w)
    {}

    tensor(mlopen::TensorDescriptor rhs)
    : desc(std::move(rhs))
    {
        data.resize(desc.GetElementSize());
    }

    template<class G>
    tensor& generate(G g) &
    {
        this->generate_impl(g);
        return *this;
    }

    template<class G>
    tensor&& generate(G g) &&
    {
        this->generate_impl(g);
        return std::move(*this);
    }

    template<class G>
    void generate_impl(G g)
    {
        auto iterator = data.begin();
        this->for_each([&](int i, int j, int k, int m)
        {
            assert(iterator < data.end());
            *iterator = g(i, j, k, m);
            ++iterator;
        });
    }

    template<class F>
    void for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        ford(n, c, h, w)(std::move(f));
    }

    template<class F>
    void par_for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        par_ford(n, c, h, w)(std::move(f));
    }

    T& operator()(int n, int c, int h, int w)
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }

    const T& operator()(int n, int c, int h, int w) const
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }
};

struct tensor_generate
{
    template<class Tensor, class G>
    Tensor&& operator()(Tensor&& t, G g) const
    {
        return std::forward<Tensor>(t.generate(g));
    }
};

template<class T>
tensor<T> get_output_tensor(const mlopen::ConvolutionDescriptor& filter, const tensor<T>& input, const tensor<T>& weights)
{
    return tensor<T>{filter.GetForwardOutputTensor(input.desc, weights.desc)};
}

template<class T>
std::vector<T> forward_conv(const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    int in_n, in_c, in_h, in_w;
    std::tie(in_n, in_c, in_h, in_w) = mlopen::tie4(input.desc.GetLengths());

    int wei_h, wei_w;
    std::tie(std::ignore, std::ignore, wei_h, wei_w) = mlopen::tie4(weights.desc.GetLengths());

    out.par_for_each([&](int o, int w, int i, int j)
    {
        int in_off_h = i * filter.v;
        int in_off_w = j * filter.u;

        T acc = bias;
        ford(in_c, wei_h, wei_w)([&](int k, int x, int y)
        {
            int in_x = in_off_h - filter.pad_h + x;
            int in_y = in_off_w - filter.pad_w + y;
            if(in_x >= 0 && in_x < in_h && in_y >= 0 && in_y < in_w) {
                acc += input(o, k, in_x, in_y) * weights(w, k, x, y);
            }
        });
        out(o, w, i, j) = acc;
    });
    return out.data;
}

template<class T>
std::vector<T> forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int /* bias */ = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    auto in_dev = handle.Write(input.data);
    auto wei_dev = handle.Write(weights.data);
    auto out_dev = handle.Create<T>(out.data.size());

    int ret_algo_count;
    mlopenConvAlgoPerf_t perf;

    int alpha = 1, beta = 1;

    filter.FindConvFwdAlgorithm(handle,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        out.desc,
        out_dev.get(),
        1,
        &ret_algo_count,
        &perf,
        mlopenConvolutionFastest,
        NULL,
        10,
        0); // MD: Not performing exhaustiveSearch by default for now

    filter.ConvolutionForward(handle,
        &alpha,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        mlopenConvolutionFwdAlgoDirect,
        &beta,
        out.desc,
        out_dev.get(),
        NULL,
        0);

    out.data = handle.Read<T>(out_dev, out.data.size());
    return out.data;
}

struct float_equal_fn
{
    template<class T>
    bool operator()(T x, T y) const
    {
        return std::fabs(x - y) < std::max(std::numeric_limits<T>::epsilon() * std::max(x, y), std::numeric_limits<T>::epsilon());
    }
};

template<class R1, class R2>
bool float_equal_range(R1&& r1, R2&& r2)
{
    return std::distance(r1.begin(), r1.end()) == std::distance(r2.begin(), r2.end()) &&
        std::equal(r1.begin(), r1.end(), r2.begin(), float_equal_fn{});
}

template<class R1, class R2, class Op>
float accumulate_difference(R1&& r1, R2&& r2, Op op)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), 0.0, op,
        [](float x, float y) { return std::fabs(x - y); }
    );
}

template<class T>
void verify_forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out_cpu = forward_conv(input, weights, filter, bias);
    auto out_gpu = forward_conv(handle, input, weights, filter, bias);
    int size = std::distance(out_cpu.begin(), out_cpu.end());
    CHECK(std::distance(out_cpu.begin(), out_cpu.end()) == std::distance(out_gpu.begin(), out_gpu.end()));
    if (!float_equal_range(out_cpu, out_gpu))
    {
        std::cout << "FAILED: " << std::endl;
        std::cout
            << "Average difference: "
            << (accumulate_difference(out_cpu, out_gpu, std::plus<float>()) / size)
            << std::endl;
        std::cout
            << "Max difference: "
            << (accumulate_difference(out_cpu, out_gpu, [](float x, float y) { return std::max(x, y); }))
            << std::endl;
    }
    // CHECK(out_cpu == out_gpu);
}

struct cross_args_apply
{
    template<class F, class T, class... Ts>
    void operator()(F f, T&& x, Ts&&... xs) const
    {
        mlopen::each_args(std::bind(f, std::forward<T>(x), std::placeholders::_1), std::forward<Ts>(xs)...);
    }
};

template<class F, class... Ts>
void cross_args(F f, Ts&&... xs)
{
    mlopen::each_args(
        std::bind(cross_args_apply{}, protect(std::move(f)), std::placeholders::_1, std::forward<Ts>(xs)...),
    std::forward<Ts>(xs)...);
}

template<class T>
struct verify_both
{
    template<class G1, class G2>
    void operator()(mlopen::Handle& handle, G1 g1, G2 g2) const
    {
        visit_network<T>([&](mlopen::TensorDescriptor input_desc, mlopen::TensorDescriptor weights_desc)
        {
            auto input = tensor<T>{std::move(input_desc)}.generate(g1);
            auto weights = tensor<T>{std::move(weights_desc)}.generate(g2);
            mlopen::ConvolutionDescriptor filter{1, 1};

            std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
            std::cout << "Weights tensor: " << weights.desc.ToString() << std::endl;

            verify_forward_conv(handle, input, weights, filter);
        });
    }
};

template<class T, class... Gs>
void verify_all(mlopen::Handle& handle, Gs... gs)
{
    cross_args(
        std::bind(verify_both<T>{}, std::ref(handle), std::placeholders::_1, std::placeholders::_2),
        gs...);
}

template<class T, class G>
void verify_one(mlopen::Handle& handle, G g)
{
    auto input = tensor<T>{16, 32, 8, 8}.generate(g);
    auto weights = tensor<T>{64, 32, 5, 5}.generate(g);
    mlopen::ConvolutionDescriptor filter{1, 1};
    verify_forward_conv(handle, input, weights, filter);
}

int main() {
    mlopen::Handle handle;
    auto g0 = [](int, int, int, int) { return 0; };
    auto g1 = [](int, int, int, int) { return 1; };
    auto g_id = [](int, int, int h, int w) { return h == w ? 1 : 0; };
    auto g = [](int n, int c, int h, int w)
    {
        double x = (547*n+701*c+877*h+1049*w+173)%1223;
        return x/691.0;
    };
    (void)g0;
    (void)g1;
    (void)g_id;
    (void)g;
#if MLOPEN_TEST_ALL
    printf("verify_all\n");
    verify_all<float>(handle, g0,g1, g_id, g);
#else
    printf("verify_one\n");
    verify_one<float>(handle, g);
#endif
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include "tcframe_test_commons.cpp"
#include "tcframe/problem.hpp"

using tcframe::BaseProblem;

class MyProblem : public BaseProblem {
protected:
    void Config() {
        setSlug("foo");
        setTimeLimit(2);
        setMemoryLimit(256);
    }

    void InputFormat() { }

    void OutputFormat() { }
};

TEST(ProblemTest, DefaultOptions) {
    BaseProblem* problem = new DefaultProblem();

    EXPECT_EQ("problem", problem->getSlug());
    EXPECT_EQ(0, problem->getTimeLimit());
    EXPECT_EQ(0, problem->getMemoryLimit());
}

TEST(ProblemTest, MyOptions) {
    BaseProblem* problem = new MyProblem();
    problem->applyProblemConfiguration();

    EXPECT_EQ("foo", problem->getSlug());
    EXPECT_EQ(2, problem->getTimeLimit());
    EXPECT_EQ(256, problem->getMemoryLimit());
}
<commit_msg>Add Problem's command-line options tests<commit_after>#include "gtest/gtest.h"

#include "tcframe_test_commons.cpp"
#include "tcframe/problem.hpp"

using tcframe::BaseProblem;

class MyProblem : public BaseProblem {
protected:
    void Config() {
        setSlug("foo");
        setTimeLimit(2);
        setMemoryLimit(256);
    }

    void InputFormat() { }

    void OutputFormat() { }
};

TEST(ProblemTest, DefaultOptions) {
    BaseProblem* problem = new DefaultProblem();

    EXPECT_EQ("problem", problem->getSlug());
    EXPECT_EQ(0, problem->getTimeLimit());
    EXPECT_EQ(0, problem->getMemoryLimit());
}

TEST(ProblemTest, MyOptions) {
    BaseProblem* problem = new MyProblem();
    problem->applyProblemConfiguration();

    EXPECT_EQ("foo", problem->getSlug());
    EXPECT_EQ(2, problem->getTimeLimit());
    EXPECT_EQ(256, problem->getMemoryLimit());
}

TEST(ProblemTest, CommandLineOptions) {
    char* argv[] = {(char*) "<runner>", (char*)"--slug=bar", (char*)"--time-limit=3", (char*)"--memory-limit=64"};

    BaseProblem* problem = new MyProblem();
    problem->applyProblemConfiguration();
    problem->applyProblemCommandLineOptions(4, argv);

    EXPECT_EQ("bar", problem->getSlug());
    EXPECT_EQ(3, problem->getTimeLimit());
    EXPECT_EQ(64, problem->getMemoryLimit());
}

TEST(ProblemTest, CommandLineOptionsWithNos) {
    char* argv[] = {(char*) "<runner>", (char*)"--no-time-limit", (char*)"--no-memory-limit"};

    BaseProblem* problem = new MyProblem();
    problem->applyProblemConfiguration();
    problem->applyProblemCommandLineOptions(3, argv);

    EXPECT_EQ("foo", problem->getSlug());
    EXPECT_EQ(0, problem->getTimeLimit());
    EXPECT_EQ(0, problem->getMemoryLimit());
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cstdint>
#include <tuple>

#include <mp++/integer.hpp>
#include <mp++/real128.hpp>

#include "catch.hpp"

using namespace mppp;

using int_t = integer<1>;

TEST_CASE("real128 get_ieee()")
{
    std::uint_least8_t sign;
    std::uint_least16_t exp;
    std::uint_least64_t hi;
    std::uint_least64_t lo;
    std::tie(sign, exp, hi, lo) = real128{}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{-0.}.get_ieee();
    REQUIRE(sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{42}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 16388ul);
    REQUIRE(hi == 10ull << (48 - 5));
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{-42}.get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 16388ul);
    REQUIRE(hi == 10ull << (48 - 5));
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128_nan().get_ieee();
    REQUIRE(exp == 32767ul);
    REQUIRE((!hi || !lo));
    std::tie(sign, exp, hi, lo) = real128_inf().get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 32767ul);
    REQUIRE((!hi && !lo));
    std::tie(sign, exp, hi, lo) = (-real128_inf()).get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 32767ul);
    REQUIRE((!hi && !lo));
    std::tie(sign, exp, hi, lo) = real128{"1.189731495357231765085759326628007e4932"}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 32766ul);
    REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48));
    REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64));
    std::tie(sign, exp, hi, lo) = real128{"-1.189731495357231765085759326628007e4932"}.get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 32766ul);
    REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48));
    REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64));
    std::tie(sign, exp, hi, lo) = real128{"6.47517511943802511092443895822764655e-4966"}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(lo == 1u);
    std::tie(sign, exp, hi, lo) = real128{"-6.47517511943802511092443895822764655e-4966"}.get_ieee();
    REQUIRE(sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(lo == 1u);
}
<commit_msg>Fix bug in the real128 test suite.<commit_after>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cstdint>
#include <tuple>

#include <mp++/integer.hpp>
#include <mp++/real128.hpp>

#include "catch.hpp"

using namespace mppp;

using int_t = integer<1>;

TEST_CASE("real128 get_ieee()")
{
    std::uint_least8_t sign;
    std::uint_least16_t exp;
    std::uint_least64_t hi;
    std::uint_least64_t lo;
    std::tie(sign, exp, hi, lo) = real128{}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{-0.}.get_ieee();
    REQUIRE(sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{42}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 16388ul);
    REQUIRE(hi == 10ull << (48 - 5));
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128{-42}.get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 16388ul);
    REQUIRE(hi == 10ull << (48 - 5));
    REQUIRE(!lo);
    std::tie(sign, exp, hi, lo) = real128_nan().get_ieee();
    REQUIRE(exp == 32767ul);
    REQUIRE((hi || lo));
    std::tie(sign, exp, hi, lo) = real128_inf().get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 32767ul);
    REQUIRE((!hi && !lo));
    std::tie(sign, exp, hi, lo) = (-real128_inf()).get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 32767ul);
    REQUIRE((!hi && !lo));
    std::tie(sign, exp, hi, lo) = real128{"1.189731495357231765085759326628007e4932"}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(exp == 32766ul);
    REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48));
    REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64));
    std::tie(sign, exp, hi, lo) = real128{"-1.189731495357231765085759326628007e4932"}.get_ieee();
    REQUIRE(sign);
    REQUIRE(exp == 32766ul);
    REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48));
    REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64));
    std::tie(sign, exp, hi, lo) = real128{"6.47517511943802511092443895822764655e-4966"}.get_ieee();
    REQUIRE(!sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(lo == 1u);
    std::tie(sign, exp, hi, lo) = real128{"-6.47517511943802511092443895822764655e-4966"}.get_ieee();
    REQUIRE(sign);
    REQUIRE(!exp);
    REQUIRE(!hi);
    REQUIRE(lo == 1u);
}
<|endoftext|>


<commit_before>#include "MS5837.h"
#include <Wire.h>

#define MS5837_ADDR               0x76
#define MS5837_RESET              0x1E
#define MS5837_ADC_READ           0x00
#define MS5837_PROM_READ          0xA0
#define MS5837_CONVERT_D1_8192    0x4A
#define MS5837_CONVERT_D2_8192    0x5A

const float MS5837::Pa = 100.0f;
const float MS5837::bar = 0.001f;
const float MS5837::mbar = 1.0f;

const uint8_t MS5837::MS5837_30BA = 0;
const uint8_t MS5837::MS5837_02BA = 1;

MS5837::MS5837() {
	fluidDensity = 1029;
}

bool MS5837::init() {
	// Reset the MS5837, per datasheet
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_RESET);
	Wire.endTransmission();

	// Wait for reset to complete
	delay(10);

	// Read calibration values and CRC
	for ( uint8_t i = 0 ; i < 7 ; i++ ) {
		Wire.beginTransmission(MS5837_ADDR);
		Wire.write(MS5837_PROM_READ+i*2);
		Wire.endTransmission();

		Wire.requestFrom(MS5837_ADDR,2);
		C[i] = (Wire.read() << 8) | Wire.read();
	}

	// Verify that data is correct with CRC
	uint8_t crcRead = C[0] >> 12;
	uint8_t crcCalculated = crc4(C);

	if ( crcCalculated == crcRead ) {
		return true; // Initialization success
	}

	return false; // CRC fail
}

void MS5837::setModel(uint8_t model) {
	_model = model;
}

void MS5837::setFluidDensity(float density) {
	fluidDensity = density;
}

void MS5837::read() {
	// Request D1 conversion
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_CONVERT_D1_8192);
	Wire.endTransmission();

	delay(20); // Max conversion time per datasheet

	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_ADC_READ);
	Wire.endTransmission();

 	Wire.requestFrom(MS5837_ADDR,3);
	D1 = 0;
	D1 = Wire.read();
	D1 = (D1 << 8) | Wire.read();
	D1 = (D1 << 8) | Wire.read();

	// Request D2 conversion
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_CONVERT_D2_8192);
	Wire.endTransmission();

	delay(20); // Max conversion time per datasheet

	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_ADC_READ);
	Wire.endTransmission();

	Wire.requestFrom(MS5837_ADDR,3);
	D2 = 0;
	D2 = Wire.read();
	D2 = (D2 << 8) | Wire.read();
	D2 = (D2 << 8) | Wire.read();

	calculate();
}

void MS5837::calculate() {
	// Given C1-C6 and D1, D2, calculated TEMP and P
	// Do conversion first and then second order temp compensation

	int32_t dT = 0;
	int64_t SENS = 0;
	int64_t OFF = 0;
	int32_t SENSi = 0;
	int32_t OFFi = 0;
	int32_t Ti = 0;
	int64_t OFF2 = 0;
	int64_t SENS2 = 0;

	// Terms called
	dT = D2-uint32_t(C[5])*256l;
	if ( _model == MS5837_02BA ) {
		SENS = int64_t(C[1])*65536l+(int64_t(C[3])*dT)/128l;
		OFF = int64_t(C[2])*131072l+(int64_t(C[4])*dT)/64l;
		P = (D1*SENS/(2097152l)-OFF)/(32768l);
	} else {
		SENS = int64_t(C[1])*32768l+(int64_t(C[3])*dT)/256l;
		OFF = int64_t(C[2])*65536l+(int64_t(C[4])*dT)/128l;
		P = (D1*SENS/(2097152l)-OFF)/(8192l);
	}

	// Temp conversion
	TEMP = 2000l+int64_t(dT)*C[6]/8388608LL;

	//Second order compensation
	if ( _model == MS5837_02BA ) {
		if((TEMP/100)<20){         //Low temp
			Ti = (11*int64_t(dT)*int64_t(dT))/(34359738368LL);
			OFFi = (31*(TEMP-2000)*(TEMP-2000))/8;
			SENSi = (63*(TEMP-2000)*(TEMP-2000))/32;
		}
	} else {
		if((TEMP/100)<20){         //Low temp
			Ti = (3*int64_t(dT)*int64_t(dT))/(8589934592LL);
			OFFi = (3*(TEMP-2000)*(TEMP-2000))/2;
			SENSi = (5*(TEMP-2000)*(TEMP-2000))/8;
			if((TEMP/100)<-15){    //Very low temp
				OFFi = OFFi+7*(TEMP+1500l)*(TEMP+1500l);
				SENSi = SENSi+4*(TEMP+1500l)*(TEMP+1500l);
			}
		}
		else if((TEMP/100)>=20){    //High temp
			Ti = 2*(dT*dT)/(137438953472LL);
			OFFi = (1*(TEMP-2000)*(TEMP-2000))/16;
			SENSi = 0;
		}
	}

	OFF2 = OFF-OFFi;           //Calculate pressure and temp second order
	SENS2 = SENS-SENSi;

	TEMP = (TEMP-Ti);

	if ( _model == MS5837_02BA ) {
		P = (((D1*SENS2)/2097152l-OFF2)/32768l);
	} else {
		P = (((D1*SENS2)/2097152l-OFF2)/8192l);
	}
}

float MS5837::pressure(float conversion) {
    if ( _model == MS5837_02BA ) {
        return P*conversion/100.0f;
    }
    else {
        return P*conversion/10.0f;
    }
}

float MS5837::temperature() {
	return TEMP/100.0f;
}

float MS5837::depth() {
	return (pressure(MS5837::Pa)-101300)/(fluidDensity*9.80665);
}

float MS5837::altitude() {
	return (1-pow((pressure()/1013.25),.190284))*145366.45*.3048;
}

uint8_t MS5837::crc4(uint16_t n_prom[]) {
	uint16_t n_rem = 0;

	n_prom[0] = ((n_prom[0]) & 0x0FFF);
	n_prom[7] = 0;

	for ( uint8_t i = 0 ; i < 16; i++ ) {
		if ( i%2 == 1 ) {
			n_rem ^= (uint16_t)((n_prom[i>>1]) & 0x00FF);
		} else {
			n_rem ^= (uint16_t)(n_prom[i>>1] >> 8);
		}
		for ( uint8_t n_bit = 8 ; n_bit > 0 ; n_bit-- ) {
			if ( n_rem & 0x8000 ) {
				n_rem = (n_rem << 1) ^ 0x3000;
			} else {
				n_rem = (n_rem << 1);
			}
		}
	}

	n_rem = ((n_rem >> 12) & 0x000F);

	return n_rem ^ 0x00;
}
<commit_msg>ms5837: add comment about depth calculation<commit_after>#include "MS5837.h"
#include <Wire.h>

#define MS5837_ADDR               0x76
#define MS5837_RESET              0x1E
#define MS5837_ADC_READ           0x00
#define MS5837_PROM_READ          0xA0
#define MS5837_CONVERT_D1_8192    0x4A
#define MS5837_CONVERT_D2_8192    0x5A

const float MS5837::Pa = 100.0f;
const float MS5837::bar = 0.001f;
const float MS5837::mbar = 1.0f;

const uint8_t MS5837::MS5837_30BA = 0;
const uint8_t MS5837::MS5837_02BA = 1;

MS5837::MS5837() {
	fluidDensity = 1029;
}

bool MS5837::init() {
	// Reset the MS5837, per datasheet
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_RESET);
	Wire.endTransmission();

	// Wait for reset to complete
	delay(10);

	// Read calibration values and CRC
	for ( uint8_t i = 0 ; i < 7 ; i++ ) {
		Wire.beginTransmission(MS5837_ADDR);
		Wire.write(MS5837_PROM_READ+i*2);
		Wire.endTransmission();

		Wire.requestFrom(MS5837_ADDR,2);
		C[i] = (Wire.read() << 8) | Wire.read();
	}

	// Verify that data is correct with CRC
	uint8_t crcRead = C[0] >> 12;
	uint8_t crcCalculated = crc4(C);

	if ( crcCalculated == crcRead ) {
		return true; // Initialization success
	}

	return false; // CRC fail
}

void MS5837::setModel(uint8_t model) {
	_model = model;
}

void MS5837::setFluidDensity(float density) {
	fluidDensity = density;
}

void MS5837::read() {
	// Request D1 conversion
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_CONVERT_D1_8192);
	Wire.endTransmission();

	delay(20); // Max conversion time per datasheet

	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_ADC_READ);
	Wire.endTransmission();

 	Wire.requestFrom(MS5837_ADDR,3);
	D1 = 0;
	D1 = Wire.read();
	D1 = (D1 << 8) | Wire.read();
	D1 = (D1 << 8) | Wire.read();

	// Request D2 conversion
	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_CONVERT_D2_8192);
	Wire.endTransmission();

	delay(20); // Max conversion time per datasheet

	Wire.beginTransmission(MS5837_ADDR);
	Wire.write(MS5837_ADC_READ);
	Wire.endTransmission();

	Wire.requestFrom(MS5837_ADDR,3);
	D2 = 0;
	D2 = Wire.read();
	D2 = (D2 << 8) | Wire.read();
	D2 = (D2 << 8) | Wire.read();

	calculate();
}

void MS5837::calculate() {
	// Given C1-C6 and D1, D2, calculated TEMP and P
	// Do conversion first and then second order temp compensation

	int32_t dT = 0;
	int64_t SENS = 0;
	int64_t OFF = 0;
	int32_t SENSi = 0;
	int32_t OFFi = 0;
	int32_t Ti = 0;
	int64_t OFF2 = 0;
	int64_t SENS2 = 0;

	// Terms called
	dT = D2-uint32_t(C[5])*256l;
	if ( _model == MS5837_02BA ) {
		SENS = int64_t(C[1])*65536l+(int64_t(C[3])*dT)/128l;
		OFF = int64_t(C[2])*131072l+(int64_t(C[4])*dT)/64l;
		P = (D1*SENS/(2097152l)-OFF)/(32768l);
	} else {
		SENS = int64_t(C[1])*32768l+(int64_t(C[3])*dT)/256l;
		OFF = int64_t(C[2])*65536l+(int64_t(C[4])*dT)/128l;
		P = (D1*SENS/(2097152l)-OFF)/(8192l);
	}

	// Temp conversion
	TEMP = 2000l+int64_t(dT)*C[6]/8388608LL;

	//Second order compensation
	if ( _model == MS5837_02BA ) {
		if((TEMP/100)<20){         //Low temp
			Ti = (11*int64_t(dT)*int64_t(dT))/(34359738368LL);
			OFFi = (31*(TEMP-2000)*(TEMP-2000))/8;
			SENSi = (63*(TEMP-2000)*(TEMP-2000))/32;
		}
	} else {
		if((TEMP/100)<20){         //Low temp
			Ti = (3*int64_t(dT)*int64_t(dT))/(8589934592LL);
			OFFi = (3*(TEMP-2000)*(TEMP-2000))/2;
			SENSi = (5*(TEMP-2000)*(TEMP-2000))/8;
			if((TEMP/100)<-15){    //Very low temp
				OFFi = OFFi+7*(TEMP+1500l)*(TEMP+1500l);
				SENSi = SENSi+4*(TEMP+1500l)*(TEMP+1500l);
			}
		}
		else if((TEMP/100)>=20){    //High temp
			Ti = 2*(dT*dT)/(137438953472LL);
			OFFi = (1*(TEMP-2000)*(TEMP-2000))/16;
			SENSi = 0;
		}
	}

	OFF2 = OFF-OFFi;           //Calculate pressure and temp second order
	SENS2 = SENS-SENSi;

	TEMP = (TEMP-Ti);

	if ( _model == MS5837_02BA ) {
		P = (((D1*SENS2)/2097152l-OFF2)/32768l);
	} else {
		P = (((D1*SENS2)/2097152l-OFF2)/8192l);
	}
}

float MS5837::pressure(float conversion) {
    if ( _model == MS5837_02BA ) {
        return P*conversion/100.0f;
    }
    else {
        return P*conversion/10.0f;
    }
}

float MS5837::temperature() {
	return TEMP/100.0f;
}

// The pressure sensor measures absolute pressure, so it will measure the atmospheric pressure + water pressure
// We subtract the atmospheric pressure to calculate the depth with only the water pressure
// The average atmospheric pressure of 101300 pascal is used for the calcuation, but atmospheric pressure varies
// If the atmospheric pressure is not 101300 at the time of reading, the depth reported will be offset
// In order to calculate the correct depth, the actual atmospheric pressure should be measured once in air, and
// that value should subtracted for subsequent depth calculations.
float MS5837::depth() {
	return (pressure(MS5837::Pa)-101300)/(fluidDensity*9.80665);
}

float MS5837::altitude() {
	return (1-pow((pressure()/1013.25),.190284))*145366.45*.3048;
}

uint8_t MS5837::crc4(uint16_t n_prom[]) {
	uint16_t n_rem = 0;

	n_prom[0] = ((n_prom[0]) & 0x0FFF);
	n_prom[7] = 0;

	for ( uint8_t i = 0 ; i < 16; i++ ) {
		if ( i%2 == 1 ) {
			n_rem ^= (uint16_t)((n_prom[i>>1]) & 0x00FF);
		} else {
			n_rem ^= (uint16_t)(n_prom[i>>1] >> 8);
		}
		for ( uint8_t n_bit = 8 ; n_bit > 0 ; n_bit-- ) {
			if ( n_rem & 0x8000 ) {
				n_rem = (n_rem << 1) ^ 0x3000;
			} else {
				n_rem = (n_rem << 1);
			}
		}
	}

	n_rem = ((n_rem >> 12) & 0x000F);

	return n_rem ^ 0x00;
}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.

// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <http://unlicense.org/>

// C++ implementation of Dmitry Vyukov's non-intrusive lock free unbounded MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
/*
 * File:   MPSCQueue.hpp
 * Author: Barath Kannan
 * This is an adaptation of https://github.com/mstump/queues/blob/master/include/mpsc-queue.hpp
 * The queue has been modified such that it can also be used as a blocking queue
 * Aligned storage was removed, was causing segmentation faults and didn't improve performance
 * Created on 14 June 2016, 1:14 AM
 */

#ifndef MPSCQUEUE_HPP
#define MPSCQUEUE_HPP

#include <atomic>
#include <shared_mutex>
#include <condition_variable>
#include <chrono>
#include <thread>
#include <assert.h>

namespace BSignals{ namespace details{

template<typename T>
class MPSCQueue{
public:

    MPSCQueue() :
        _head(new buffer_node_t),
        _tail(_head.load(std::memory_order_relaxed)){
        buffer_node_t* front = _head.load(std::memory_order_relaxed);
        front->next.store(nullptr, std::memory_order_relaxed);
    }

    ~MPSCQueue(){
        T output;
        while (this->dequeue(output)) {}
        buffer_node_t* front = _head.load(std::memory_order_relaxed);
        delete front;
    }

    void enqueue(const T& input){
        buffer_node_t* node = (new buffer_node_t);
        node->data = input;
        node->next.store(nullptr, std::memory_order_relaxed);

        buffer_node_t* prev_head = _head.exchange(node, std::memory_order_acq_rel);
        prev_head->next.store(node, std::memory_order_release);

        std::shared_lock<std::shared_timed_mutex> lock(_mutex);
        if (waitingReader){
            _cv.notify_one();
        }
    }

    bool dequeue(T& output){
        buffer_node_t* tail = _tail.load(std::memory_order_relaxed);
        buffer_node_t* next = tail->next.load(std::memory_order_acquire);

        if (next == nullptr) {
            return false;
        }

        output = next->data;
        _tail.store(next, std::memory_order_release);
        delete tail;
        return true;
    }

    void blockingDequeue(T& output){
        std::unique_lock<std::shared_timed_mutex> lock(_mutex);
        waitingReader = true;
        while (!dequeue(output)){
            _cv.wait(lock);
        }
        waitingReader = false;
    }

private:

    struct buffer_node_t{
        T                           data;
        std::atomic<buffer_node_t*> next;
    };

    std::atomic<buffer_node_t*> _head;
    std::atomic<buffer_node_t*> _tail;
    std::shared_timed_mutex _mutex;
    std::condition_variable_any _cv;
    bool waitingReader{false};

    MPSCQueue(const MPSCQueue&) {}
    void operator=(const MPSCQueue&) {}
};
}}

#endif
<commit_msg>clean up, format consistency<commit_after>// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.

// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <http://unlicense.org/>

// C++ implementation of Dmitry Vyukov's non-intrusive lock free unbounded MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
/*
 * File:   MPSCQueue.hpp
 * Author: Barath Kannan
 * This is an adaptation of https://github.com/mstump/queues/blob/master/include/mpsc-queue.hpp
 * The queue has been modified such that it can also be used as a blocking queue
 * Aligned storage was removed, was causing segmentation faults and didn't improve performance
 * Created on 14 June 2016, 1:14 AM
 */

#ifndef MPSCQUEUE_HPP
#define MPSCQUEUE_HPP

#include <atomic>
#include <shared_mutex>
#include <condition_variable>
#include <chrono>
#include <thread>
#include <assert.h>

namespace BSignals{ namespace details{

template<typename T>
class MPSCQueue{
public:

    MPSCQueue() :
        _head(new listNode),
        _tail(_head.load(std::memory_order_relaxed)){}

    ~MPSCQueue(){
        T output;
        while (this->dequeue(output)) {}
        listNode* front = _head.load(std::memory_order_relaxed);
        delete front;
    }

    void enqueue(const T& input){
        listNode* node = new listNode{input};

        listNode* prev_head = _head.exchange(node, std::memory_order_acq_rel);
        prev_head->next.store(node, std::memory_order_release);

        std::shared_lock<std::shared_timed_mutex> lock(_mutex);
        if (waitingReader) _cv.notify_one();
    }

    bool dequeue(T& output){
        listNode* tail = _tail.load(std::memory_order_relaxed);
        listNode* next = tail->next.load(std::memory_order_acquire);
        if (next == nullptr) return false;

        output = next->data;
        _tail.store(next, std::memory_order_release);
        delete tail;
        return true;
    }

    void blockingDequeue(T& output){
        std::unique_lock<std::shared_timed_mutex> lock(_mutex);
        waitingReader = true;
        while (!dequeue(output)){
            _cv.wait(lock);
        }
        waitingReader = false;
    }

private:
    struct listNode{
        T                           data;
        std::atomic<listNode*> next{nullptr};
    };

    std::atomic<listNode*> _head;
    std::atomic<listNode*> _tail;
    std::shared_timed_mutex _mutex;
    std::condition_variable_any _cv;
    bool waitingReader{false};

    MPSCQueue(const MPSCQueue&) {}
    void operator=(const MPSCQueue&) {}
};
}}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Algorithm.hpp>
#include <string>

// Functions args
bool NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<bool>)
{
	return instance.CheckBoolean(index);
}

double NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<double>)
{
	return instance.CheckNumber(index);
}

float NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<float>)
{
	return instance.CheckNumber(index);
}

int NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<int>)
{
	return instance.CheckInteger(index);
}

std::string NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<std::string>)
{
	return instance.CheckString(index);
}

NzString NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<NzString>)
{
	return instance.CheckString(index);
}

template<typename T>
T NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<const T&>)
{
	return NzLuaImplQueryArg(instance, index, NzTypeTag<T>());
}

template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, T> NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<T>)
{
	return static_cast<T>(NzLuaImplQueryArg(instance, index, NzTypeTag<typename std::make_signed<T>::type>()));
}

// Function returns
int NzLuaImplReplyVal(NzLuaInstance& instance, bool&& val, NzTypeTag<bool>)
{
	instance.PushBoolean(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, double&& val, NzTypeTag<double>)
{
	instance.PushNumber(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, float&& val, NzTypeTag<float>)
{
	instance.PushNumber(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, int&& val, NzTypeTag<int>)
{
	instance.PushInteger(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, std::string&& val, NzTypeTag<std::string>)
{
	instance.PushString(val.c_str(), val.size());
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, NzString&& val, NzTypeTag<NzString>)
{
	instance.PushString(std::move(val));
	return 1;
}

template<typename T1, typename T2>
int NzLuaImplReplyVal(NzLuaInstance& instance, std::pair<T1, T2>&& val, NzTypeTag<std::pair<T1, T2>>)
{
	int retVal = 0;

	retVal += NzLuaImplReplyVal(instance, std::move(val.first), NzTypeTag<T1>());
	retVal += NzLuaImplReplyVal(instance, std::move(val.second), NzTypeTag<T2>());

	return retVal;
}

template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, int> NzLuaImplReplyVal(NzLuaInstance& instance, T&& val, NzTypeTag<T>)
{
	using SignedT = typename std::make_signed<T>::type;

	return NzLuaImplReplyVal(instance, val, NzTypeTag<SignedT>());
}

template<typename... Args>
class NzLuaImplFunctionProxy
{
	public:
		NzLuaImplFunctionProxy(NzLuaInstance& instance) :
		m_instance(instance)
		{
		}

		template<unsigned int N, typename ArgType>
		void ProcessArgs()
		{
			std::get<N>(m_args) = std::move(NzLuaImplQueryArg(m_instance, N+1, NzTypeTag<ArgType>()));
		}

		template<int N, typename ArgType1, typename ArgType2, typename... Rest>
		void ProcessArgs()
		{
			ProcessArgs<N, ArgType1>();
			ProcessArgs<N+1, ArgType2, Rest...>();
		}

		void ProcessArgs()
		{
			ProcessArgs<0, Args...>();
		}

		int Invoke(void (*func)(Args...))
		{
			NzApply(func, m_args);
			return 0;
		}

		template<typename Ret>
		int Invoke(Ret (*func)(Args...))
		{
			return NzLuaImplReplyVal(m_instance, std::move(NzApply(func, m_args)), NzTypeTag<decltype(NzApply(func, m_args))>());
		}

	private:
		NzLuaInstance& m_instance;
		std::tuple<Args...> m_args;
};

template<typename R, typename... Args>
void NzLuaInstance::PushFunction(R(*func)(Args...))
{
	PushFunction([func](NzLuaInstance& instance) -> int
	{
		NzLuaImplFunctionProxy<Args...> handler(instance);
        handler.ProcessArgs();

		return handler.Invoke(func);
	});
}
<commit_msg>Lua/LuaInstance: Fix warning + optimizations<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Lua scripting module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Algorithm.hpp>
#include <string>

// Functions args
bool NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<bool>)
{
	return instance.CheckBoolean(index);
}

double NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<double>)
{
	return instance.CheckNumber(index);
}

float NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<float>)
{
	return static_cast<float>(instance.CheckNumber(index));
}

int NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<int>)
{
	return static_cast<int>(instance.CheckInteger(index));
}

std::string NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<std::string>)
{
	std::size_t strLength = 0;
	const char* str = instance.CheckString(index, &strLength);

	return std::string(str, strLength);
}

NzString NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<NzString>)
{
	std::size_t strLength = 0;
	const char* str = instance.CheckString(index, &strLength);

	return NzString(str, strLength);
}

template<typename T>
T NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<const T&>)
{
	return NzLuaImplQueryArg(instance, index, NzTypeTag<T>());
}

template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, T> NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<T>)
{
	return static_cast<T>(NzLuaImplQueryArg(instance, index, NzTypeTag<typename std::make_signed<T>::type>()));
}

// Function returns
int NzLuaImplReplyVal(NzLuaInstance& instance, bool&& val, NzTypeTag<bool>)
{
	instance.PushBoolean(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, double&& val, NzTypeTag<double>)
{
	instance.PushNumber(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, float&& val, NzTypeTag<float>)
{
	instance.PushNumber(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, int&& val, NzTypeTag<int>)
{
	instance.PushInteger(val);
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, std::string&& val, NzTypeTag<std::string>)
{
	instance.PushString(val.c_str(), val.size());
	return 1;
}

int NzLuaImplReplyVal(NzLuaInstance& instance, NzString&& val, NzTypeTag<NzString>)
{
	instance.PushString(std::move(val));
	return 1;
}

template<typename T1, typename T2>
int NzLuaImplReplyVal(NzLuaInstance& instance, std::pair<T1, T2>&& val, NzTypeTag<std::pair<T1, T2>>)
{
	int retVal = 0;

	retVal += NzLuaImplReplyVal(instance, std::move(val.first), NzTypeTag<T1>());
	retVal += NzLuaImplReplyVal(instance, std::move(val.second), NzTypeTag<T2>());

	return retVal;
}

template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, int> NzLuaImplReplyVal(NzLuaInstance& instance, T&& val, NzTypeTag<T>)
{
	using SignedT = typename std::make_signed<T>::type;

	return NzLuaImplReplyVal(instance, val, NzTypeTag<SignedT>());
}

template<typename... Args>
class NzLuaImplFunctionProxy
{
	public:
		NzLuaImplFunctionProxy(NzLuaInstance& instance) :
		m_instance(instance)
		{
		}

		template<unsigned int N, typename ArgType>
		void ProcessArgs()
		{
			std::get<N>(m_args) = std::move(NzLuaImplQueryArg(m_instance, N+1, NzTypeTag<ArgType>()));
		}

		template<int N, typename ArgType1, typename ArgType2, typename... Rest>
		void ProcessArgs()
		{
			ProcessArgs<N, ArgType1>();
			ProcessArgs<N+1, ArgType2, Rest...>();
		}

		void ProcessArgs()
		{
			ProcessArgs<0, Args...>();
		}

		int Invoke(void (*func)(Args...))
		{
			NzApply(func, m_args);
			return 0;
		}

		template<typename Ret>
		int Invoke(Ret (*func)(Args...))
		{
			return NzLuaImplReplyVal(m_instance, std::move(NzApply(func, m_args)), NzTypeTag<decltype(NzApply(func, m_args))>());
		}

	private:
		NzLuaInstance& m_instance;
		std::tuple<Args...> m_args;
};

template<typename R, typename... Args>
void NzLuaInstance::PushFunction(R(*func)(Args...))
{
	PushFunction([func](NzLuaInstance& instance) -> int
	{
		NzLuaImplFunctionProxy<Args...> handler(instance);
        handler.ProcessArgs();

		return handler.Invoke(func);
	});
}
<|endoftext|>


<commit_before><commit_msg>coverity#1269591 Uncaught exception<commit_after><|endoftext|>


<commit_before>#pragma once

#include "clam/config.h"

namespace clam {

////
// Base numerical domains for user options
////
enum CrabDomain
  {   INTERVALS
      , INTERVALS_CONGRUENCES
      , BOXES
      , DIS_INTERVALS
      /*, ZONES_SPARSE_DBM*/
      , ZONES_SPLIT_DBM
      , TERMS_INTERVALS
      , TERMS_DIS_INTERVALS
      //TERMS_INTERVALS x  ZONES_SPLIT_DBM
      , TERMS_ZONES
      //(#live vars<threshold ? TERMS_INTERVALSxZONES_SPLIT_DBM, INTERVALS)
      , ADAPT_TERMS_ZONES
      , OCT
      , PK
      , WRAPPED_INTERVALS
  };

////
// Kind of checker
////
enum assert_check_kind_t
  { NOCHECKS = 0,
    ASSERTION = 1,
    NULLITY = 2
  };

/**
* Class to set analysis options
 **/
struct AnalysisParams {
  CrabDomain dom;
#ifndef TOP_DOWN_INTER_ANALYSIS
  CrabDomain sum_dom;
#endif
  bool run_backward;
  bool run_liveness;
  bool run_inter;
#ifdef TOP_DOWN_INTER_ANALYSIS
  unsigned int max_calling_contexts;
#endif
  unsigned relational_threshold;
  unsigned widening_delay;
  unsigned narrowing_iters;
  unsigned widening_jumpset;
  bool stats;
  bool print_invars;
  bool print_preconds;
  bool print_unjustified_assumptions;
  bool print_summaries;
  bool store_invariants;
  bool keep_shadow_vars;
  assert_check_kind_t check;
  unsigned check_verbose;

  AnalysisParams()
    : dom(INTERVALS),
#ifndef TOP_DOWN_INTER_ANALYSIS
      sum_dom(ZONES_SPLIT_DBM),
#endif
      run_backward(false), run_liveness(false),
      run_inter(false),
#ifdef TOP_DOWN_INTER_ANALYSIS
      max_calling_contexts(UINT_MAX),
#endif
      relational_threshold(10000),
      widening_delay(1), narrowing_iters(10), widening_jumpset(0),
      stats(false),
      print_invars(false), print_preconds(false),
      print_unjustified_assumptions(false), print_summaries(false),
      store_invariants(true), keep_shadow_vars(false),
      check(NOCHECKS), check_verbose(0) { }

  std::string abs_dom_to_str() const;

#ifndef TOP_DOWN_INTER_ANALYSIS
  std::string sum_abs_dom_to_str() const;
#endif
};

} // end namespace clam
<commit_msg>Fix compilation problems<commit_after>#pragma once

#include "clam/config.h"

#include <climits>
#include <string>

namespace clam {

////
// Base numerical domains for user options
////
enum CrabDomain
  {   INTERVALS
      , INTERVALS_CONGRUENCES
      , BOXES
      , DIS_INTERVALS
      /*, ZONES_SPARSE_DBM*/
      , ZONES_SPLIT_DBM
      , TERMS_INTERVALS
      , TERMS_DIS_INTERVALS
      //TERMS_INTERVALS x  ZONES_SPLIT_DBM
      , TERMS_ZONES
      //(#live vars<threshold ? TERMS_INTERVALSxZONES_SPLIT_DBM, INTERVALS)
      , ADAPT_TERMS_ZONES
      , OCT
      , PK
      , WRAPPED_INTERVALS
  };

////
// Kind of checker
////
enum assert_check_kind_t
  { NOCHECKS = 0,
    ASSERTION = 1,
    NULLITY = 2
  };

/**
* Class to set analysis options
 **/
struct AnalysisParams {
  CrabDomain dom;
#ifndef TOP_DOWN_INTER_ANALYSIS
  CrabDomain sum_dom;
#endif
  bool run_backward;
  bool run_liveness;
  bool run_inter;
#ifdef TOP_DOWN_INTER_ANALYSIS
  unsigned int max_calling_contexts;
#endif
  unsigned relational_threshold;
  unsigned widening_delay;
  unsigned narrowing_iters;
  unsigned widening_jumpset;
  bool stats;
  bool print_invars;
  bool print_preconds;
  bool print_unjustified_assumptions;
  bool print_summaries;
  bool store_invariants;
  bool keep_shadow_vars;
  assert_check_kind_t check;
  unsigned check_verbose;

  AnalysisParams()
    : dom(INTERVALS),
#ifndef TOP_DOWN_INTER_ANALYSIS
      sum_dom(ZONES_SPLIT_DBM),
#endif
      run_backward(false), run_liveness(false),
      run_inter(false),
#ifdef TOP_DOWN_INTER_ANALYSIS
      max_calling_contexts(UINT_MAX),
#endif
      relational_threshold(10000),
      widening_delay(1), narrowing_iters(10), widening_jumpset(0),
      stats(false),
      print_invars(false), print_preconds(false),
      print_unjustified_assumptions(false), print_summaries(false),
      store_invariants(true), keep_shadow_vars(false),
      check(NOCHECKS), check_verbose(0) { }

  std::string abs_dom_to_str() const;

#ifndef TOP_DOWN_INTER_ANALYSIS
  std::string sum_abs_dom_to_str() const;
#endif
};

} // end namespace clam
<|endoftext|>


<commit_before>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee++ -- C Trampoline Support
 *
 * This file provides support for C trampolines, that is, converting C++
 * functionals to pairs of C function pointers and @c void*.  See
 * make_c_trampoline() for details.
 *
 * This file has no dependencies on any other part of IronBee or IronBee++.
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#ifndef __IBPP__C_TRAMPOLINE__
#define __IBPP__C_TRAMPOLINE__

#include <boost/any.hpp>
#include <boost/function.hpp>

#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition.hpp>

#ifndef IRONBEEPP_C_TRAMPOLINE_MAX_ARGS
/**
 * Maximum number of arguments of a function passed to make_c_trampoline().
 *
 * Can be defined before this file is included to change how many arguments
 * are supported.  The length of this file post-preprocessing is linear in the
 * value.
 *
 * Defaults to 10.
 */
#define IRONBEEPP_C_TRAMPOLINE_MAX_ARGS 10
#endif

namespace IronBee {

/// @cond Internal
namespace c_trampoline_implementation {

//! Generates member of boost::function that contains type of argument @a n.
#define CT_ARG(n) BOOST_PP_CAT(BOOST_PP_CAT(arg, n), _type)
//! Pulls type of argument @a n into current class.
#define CT_ARG_USING(z, n, unused) \
    typedef typename type_of_function::CT_ARG(n) BOOST_PP_CAT(type_of_arg, n);
//! Defines a partial specialization of make_c_trampoline_helper for n-1 args.
#define CT_TOP(n)                                                            \
    template <>                                                              \
    struct make_c_trampoline_helper<BOOST_PP_SUB(n, 1)>                      \
    {                                                                        \
        template <typename F>                                                \
        struct impl {                                                        \
            typedef boost::function<F> type_of_function;                     \
            typedef typename type_of_function::result_type type_of_result;   \
            BOOST_PP_REPEAT_FROM_TO(1, n, CT_ARG_USING, ~)                   \
            typedef type_of_result(*type_of_cptr)(                           \
                BOOST_PP_ENUM_SHIFTED_PARAMS(n, type_of_arg),                \
                void*                                                        \
            );                                                               \
            typedef std::pair<type_of_cptr, void*> type_of_pair;             \
                                                                             \
            static type_of_result trampoline(                                \
                BOOST_PP_ENUM_SHIFTED_BINARY_PARAMS(n, type_of_arg, a),      \
                void* cdata                                                  \
            )                                                                \
            {                                                                \
                return boost::any_cast<type_of_function>(                    \
                    *reinterpret_cast<boost::any*>(cdata)                    \
                )(                                                           \
                    BOOST_PP_ENUM_SHIFTED_PARAMS(n, a)                       \
                );                                                           \
            }                                                                \
        };                                                                   \
    };

/**
 * Helper struct for make_c_trampoline().
 *
 * When @a N is between 1 and IRONBEEPP_C_TRAMPOLINE_MAX_ARGS, this struct
 * will contain an internal template @c impl, templated on the function
 * signature.  The @c impl template will define:
 *
 * - @c type_of_cptr -- Function pointer type.
 * - @c type_of_pair -- Pair of @c type_of_cptr and @c void*.
 * - @c trampoline   -- Static trampoline function.
 *
 * See implementation of make_c_trampoline() for details on usage.
 *
 * @tparam N Arity of function to make trampoline for.
 */
template <int N>
struct make_c_trampoline_helper
{
    // Error case.
};

#ifndef DOXYGEN_SKIP
#include <boost/preprocessor/iteration/local.hpp>
#define BOOST_PP_LOCAL_MACRO(n) CT_TOP(BOOST_PP_ADD(n, 1))
#define BOOST_PP_LOCAL_LIMITS   (1, IRONBEEPP_C_TRAMPOLINE_MAX_ARGS)
#include BOOST_PP_LOCAL_ITERATE()
#endif

#undef CT_ARG
#undef CT_ARG_USING
#undef CT_TOP

} // c_trampoline_impl
/// @endcond

/**
 * Convert a C++ functional of signature @a F into a C trampoline.
 *
 * Example:
 *
 * @code
 * std::pair<int(*)(int, int, void*), void*> trampoline =
 *   IronBee::make_c_trampoline<int(int, int)>(
 *     std::plus<int>()
 *   );
 * int x = trampoline.first(1, 2, trampoline.second);
 * assert(x == 3);
 * IronBee::delete_c_trampoline(x.second);
 *
 * // C++11 example.
 * auto trampoline =
 *   IronBee::make_c_trampoline<int(int, int)(
 *     [](int a, int b) {return a + b;}
 *   );
 * int x = trampoline.first(1, 2, trampoline.second);
 * assert(x == 3);
 * IronBee::delete_c_trampoline(x.second);
 * @endcode
 *
 * @tparam F Signature of @a f.  In many cases the compiler will not be able
 *           to deduce @a F from @a f and it will need to be explicitly
 *           specified.  Supports any number of arguments up to
 *           IRONBEEPP_C_TRAMPOLINE_MAX_ARGS which defaults to 10 but can be
 *           modified by defining before this file is included.
 * @param[in] f Function to convert.
 * @return pair of function pointer and @c void*.  Function pointer points to
 *         function with same return type as @a F initial arguments identical
 *         to @a F, plus a final void* argument.  When passed the @c void*
 *         portion to the final argument, will evaluate @a f with arguments
 *         and return result.  Caller is responsible for calling
 *         delete_c_trampoline() on @c void* portion to reclaim memory.
 */
template <typename F>
typename c_trampoline_implementation::make_c_trampoline_helper<
    boost::function<F>::arity
>::template impl<F>::type_of_pair
make_c_trampoline(boost::function<F> f)
{
    return std::make_pair(
        &c_trampoline_implementation::make_c_trampoline_helper<
            boost::function<F>::arity
        >::template impl<F>::trampoline,
        new boost::any(f)
    );
}

/**
 * Reclaim memory from a trampoline.
 *
 * @param[in] cdata @c void* portion of a trampoline returned from
 *                  make_c_trampoline().
 */
void delete_c_trampoline(void* cdata)
{
    delete reinterpret_cast<boost::any*>(cdata);
}

} // IronBee

#endif
<commit_msg>ironbee++/c_trampoline: Fix potential symbol collision.<commit_after>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee++ -- C Trampoline Support
 *
 * This file provides support for C trampolines, that is, converting C++
 * functionals to pairs of C function pointers and @c void*.  See
 * make_c_trampoline() for details.
 *
 * This file has no dependencies on any other part of IronBee or IronBee++.
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#ifndef __IBPP__C_TRAMPOLINE__
#define __IBPP__C_TRAMPOLINE__

#include <boost/any.hpp>
#include <boost/function.hpp>

#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition.hpp>

#ifndef IRONBEEPP_C_TRAMPOLINE_MAX_ARGS
/**
 * Maximum number of arguments of a function passed to make_c_trampoline().
 *
 * Can be defined before this file is included to change how many arguments
 * are supported.  The length of this file post-preprocessing is linear in the
 * value.
 *
 * Defaults to 10.
 */
#define IRONBEEPP_C_TRAMPOLINE_MAX_ARGS 10
#endif

namespace IronBee {

/// @cond Internal
namespace c_trampoline_implementation {

//! Generates member of boost::function that contains type of argument @a n.
#define CT_ARG(n) BOOST_PP_CAT(BOOST_PP_CAT(arg, n), _type)
//! Pulls type of argument @a n into current class.
#define CT_ARG_USING(z, n, unused) \
    typedef typename type_of_function::CT_ARG(n) BOOST_PP_CAT(type_of_arg, n);
//! Defines a partial specialization of make_c_trampoline_helper for n-1 args.
#define CT_TOP(n)                                                            \
    template <>                                                              \
    struct make_c_trampoline_helper<BOOST_PP_SUB(n, 1)>                      \
    {                                                                        \
        template <typename F>                                                \
        struct impl {                                                        \
            typedef boost::function<F> type_of_function;                     \
            typedef typename type_of_function::result_type type_of_result;   \
            BOOST_PP_REPEAT_FROM_TO(1, n, CT_ARG_USING, ~)                   \
            typedef type_of_result(*type_of_cptr)(                           \
                BOOST_PP_ENUM_SHIFTED_PARAMS(n, type_of_arg),                \
                void*                                                        \
            );                                                               \
            typedef std::pair<type_of_cptr, void*> type_of_pair;             \
                                                                             \
            static type_of_result trampoline(                                \
                BOOST_PP_ENUM_SHIFTED_BINARY_PARAMS(n, type_of_arg, a),      \
                void* cdata                                                  \
            )                                                                \
            {                                                                \
                return boost::any_cast<type_of_function>(                    \
                    *reinterpret_cast<boost::any*>(cdata)                    \
                )(                                                           \
                    BOOST_PP_ENUM_SHIFTED_PARAMS(n, a)                       \
                );                                                           \
            }                                                                \
        };                                                                   \
    };

/**
 * Helper struct for make_c_trampoline().
 *
 * When @a N is between 1 and IRONBEEPP_C_TRAMPOLINE_MAX_ARGS, this struct
 * will contain an internal template @c impl, templated on the function
 * signature.  The @c impl template will define:
 *
 * - @c type_of_cptr -- Function pointer type.
 * - @c type_of_pair -- Pair of @c type_of_cptr and @c void*.
 * - @c trampoline   -- Static trampoline function.
 *
 * See implementation of make_c_trampoline() for details on usage.
 *
 * @tparam N Arity of function to make trampoline for.
 */
template <int N>
struct make_c_trampoline_helper
{
    // Error case.
};

#ifndef DOXYGEN_SKIP
#include <boost/preprocessor/iteration/local.hpp>
#define BOOST_PP_LOCAL_MACRO(n) CT_TOP(BOOST_PP_ADD(n, 1))
#define BOOST_PP_LOCAL_LIMITS   (1, IRONBEEPP_C_TRAMPOLINE_MAX_ARGS)
#include BOOST_PP_LOCAL_ITERATE()
#endif

#undef CT_ARG
#undef CT_ARG_USING
#undef CT_TOP

} // c_trampoline_impl
/// @endcond

/**
 * Convert a C++ functional of signature @a F into a C trampoline.
 *
 * Example:
 *
 * @code
 * std::pair<int(*)(int, int, void*), void*> trampoline =
 *   IronBee::make_c_trampoline<int(int, int)>(
 *     std::plus<int>()
 *   );
 * int x = trampoline.first(1, 2, trampoline.second);
 * assert(x == 3);
 * IronBee::delete_c_trampoline(x.second);
 *
 * // C++11 example.
 * auto trampoline =
 *   IronBee::make_c_trampoline<int(int, int)(
 *     [](int a, int b) {return a + b;}
 *   );
 * int x = trampoline.first(1, 2, trampoline.second);
 * assert(x == 3);
 * IronBee::delete_c_trampoline(x.second);
 * @endcode
 *
 * @tparam F Signature of @a f.  In many cases the compiler will not be able
 *           to deduce @a F from @a f and it will need to be explicitly
 *           specified.  Supports any number of arguments up to
 *           IRONBEEPP_C_TRAMPOLINE_MAX_ARGS which defaults to 10 but can be
 *           modified by defining before this file is included.
 * @param[in] f Function to convert.
 * @return pair of function pointer and @c void*.  Function pointer points to
 *         function with same return type as @a F initial arguments identical
 *         to @a F, plus a final void* argument.  When passed the @c void*
 *         portion to the final argument, will evaluate @a f with arguments
 *         and return result.  Caller is responsible for calling
 *         delete_c_trampoline() on @c void* portion to reclaim memory.
 */
template <typename F>
typename c_trampoline_implementation::make_c_trampoline_helper<
    boost::function<F>::arity
>::template impl<F>::type_of_pair
make_c_trampoline(boost::function<F> f)
{
    return std::make_pair(
        &c_trampoline_implementation::make_c_trampoline_helper<
            boost::function<F>::arity
        >::template impl<F>::trampoline,
        new boost::any(f)
    );
}

/**
 * Reclaim memory from a trampoline.
 *
 * @param[in] cdata @c void* portion of a trampoline returned from
 *                  make_c_trampoline().
 */
inline void delete_c_trampoline(void* cdata)
{
    delete reinterpret_cast<boost::any*>(cdata);
}

} // IronBee

#endif
<|endoftext|>