thesis version
This commit is contained in:
		
							
								
								
									
										5
									
								
								tests/common.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/common.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
std::size_t _copy{};
 | 
			
		||||
std::size_t _move{};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										138
									
								
								tests/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								tests/common.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
#ifndef ALSK_TESTS_COMMON_H
 | 
			
		||||
#define ALSK_TESTS_COMMON_H
 | 
			
		||||
 | 
			
		||||
#include <numeric>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
extern std::size_t _copy;
 | 
			
		||||
extern std::size_t _move;
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct Measure {
 | 
			
		||||
	using value_type = T;
 | 
			
		||||
 | 
			
		||||
	T v;
 | 
			
		||||
 | 
			
		||||
	Measure() = default;
 | 
			
		||||
	explicit Measure(int n): v(n) {}
 | 
			
		||||
 | 
			
		||||
	Measure(T const& v): v{v} { ++_copy; }
 | 
			
		||||
	Measure(T&& v): v{std::move(v)} { ++_move; }
 | 
			
		||||
	Measure(Measure const& o): v{o.v} { ++_copy; }
 | 
			
		||||
	Measure(Measure&& o): v{std::move(o.v)} { ++_move; }
 | 
			
		||||
 | 
			
		||||
	Measure& operator=(T const& v) {
 | 
			
		||||
		this->v = v;
 | 
			
		||||
		++_copy;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Measure& operator=(T&& v) {
 | 
			
		||||
		this->v = std::move(v);
 | 
			
		||||
		++_move;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Measure& operator=(Measure const& o) {
 | 
			
		||||
		if(this == &o) return *this;
 | 
			
		||||
		this->v = o.v;
 | 
			
		||||
		++_copy;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Measure& operator=(Measure&& o) {
 | 
			
		||||
		if(this == &o) return *this;
 | 
			
		||||
		this->v = std::move(o.v);
 | 
			
		||||
		++_move;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decltype(auto) begin() const { return v.begin(); }
 | 
			
		||||
	decltype(auto) end() const { return v.end(); }
 | 
			
		||||
	decltype(auto) size() const { return v.size(); }
 | 
			
		||||
 | 
			
		||||
	decltype(auto) operator[](std::size_t i) const { return v[i]; }
 | 
			
		||||
	decltype(auto) operator[](std::size_t i) { return v[i]; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct Add {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	T operator()(T const& lhs, T const& rhs) { return lhs+rhs; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Mult {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	T operator()(T const& lhs, T const& rhs) { return lhs*rhs; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Div {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	T operator()(T const& lhs, T const& rhs) { return lhs/rhs; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Sqrt {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	T operator()(T const& lhs) { return sqrt(lhs); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct MultC {
 | 
			
		||||
	T m;
 | 
			
		||||
 | 
			
		||||
	template<typename U>
 | 
			
		||||
	auto operator()(U const& lhs) { return lhs*m; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Tupler {
 | 
			
		||||
	template<typename... Ts>
 | 
			
		||||
	auto operator()(Ts const&... values) { return std::make_tuple(values...); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* for copy/move count test */
 | 
			
		||||
template<typename Vector>
 | 
			
		||||
struct MultiplyBy {
 | 
			
		||||
	Vector coeffs;
 | 
			
		||||
 | 
			
		||||
	MultiplyBy() = default;
 | 
			
		||||
	MultiplyBy(Vector const& coeffs): coeffs{coeffs} {}
 | 
			
		||||
	MultiplyBy(Vector&& coeffs): coeffs{std::move(coeffs)} {}
 | 
			
		||||
 | 
			
		||||
	int operator()(int v) const {
 | 
			
		||||
		return std::accumulate(std::begin(coeffs), std::end(coeffs), v,
 | 
			
		||||
			[](int a, int b) { return a*b; });
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename Vector>
 | 
			
		||||
struct Process {
 | 
			
		||||
	Vector operator()(int n, int a) const {
 | 
			
		||||
		Vector v(n);
 | 
			
		||||
		for(int i = 0; i < n; ++i)
 | 
			
		||||
			v[i] = a+i;
 | 
			
		||||
		return v;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename Vector>
 | 
			
		||||
struct ProdVect {
 | 
			
		||||
	void operator()(int& r, Vector const& a, Vector const& b) const {
 | 
			
		||||
		r = 0;
 | 
			
		||||
		for(std::size_t i = 0; i < a.size(); ++i)
 | 
			
		||||
			r += a[i] * b[i];
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename Vector>
 | 
			
		||||
struct Sum {
 | 
			
		||||
	Vector operator()(Vector const& a, Vector const& b) const {
 | 
			
		||||
		Vector r(a.size());
 | 
			
		||||
		for(std::size_t i = 0; i < a.size(); ++i)
 | 
			
		||||
			r[i] = a[i] * b[i];
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										75
									
								
								tests/copy.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								tests/copy.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
#include <numeric>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
using Data = Measure<int>;
 | 
			
		||||
 | 
			
		||||
struct Opv {
 | 
			
		||||
	template<typename... Ts>
 | 
			
		||||
	void operator()(Ts&&...) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Op {
 | 
			
		||||
	template<typename... Ts>
 | 
			
		||||
	Data operator()(Ts&&...) { return {}; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* NOTE:
 | 
			
		||||
 * `Data const&` causes a copy when then stored in Data
 | 
			
		||||
 * to avoid: simply return `Data` instead or store in `Data&`
 | 
			
		||||
 * hw uses one `auto` to enables this
 | 
			
		||||
 */
 | 
			
		||||
struct Opr {
 | 
			
		||||
	template<typename... Ts>
 | 
			
		||||
	Data const& operator()(Data const& a, Ts&&...) { return a; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using Struct = S<Serial, Opv, Op, Opr, Op>;
 | 
			
		||||
using Links =
 | 
			
		||||
L<Serial, arg::R<3>(Data const&),
 | 
			
		||||
	void(arg::P<0>),
 | 
			
		||||
	Data(arg::P<0>),
 | 
			
		||||
	Data(arg::R<1> const&),
 | 
			
		||||
	Data(arg::P<0>, arg::R<1> const&, arg::R<2> const&)
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using Test = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
void hw(Data const& p0) {
 | 
			
		||||
	Opv{}(p0);
 | 
			
		||||
	decltype(auto) r1 = Op{}(p0);
 | 
			
		||||
	auto r2 = Opr{}(r1);
 | 
			
		||||
	decltype(auto) r3 = Op{}(p0, r1, r2);
 | 
			
		||||
 | 
			
		||||
	static_cast<void>(r3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Copy") {
 | 
			
		||||
	std::size_t bCopy, bMove, sCopy, sMove;
 | 
			
		||||
 | 
			
		||||
	_copy = _move = 0;
 | 
			
		||||
	hw({});
 | 
			
		||||
	bCopy = _copy;
 | 
			
		||||
	bMove = _move;
 | 
			
		||||
 | 
			
		||||
	auto test = implement<exec::Sequential, Test>();
 | 
			
		||||
 | 
			
		||||
	_copy = _move = 0;
 | 
			
		||||
	test({});
 | 
			
		||||
	sCopy = _copy;
 | 
			
		||||
	sMove = _move;
 | 
			
		||||
 | 
			
		||||
	CAPTURE(bCopy);
 | 
			
		||||
	CAPTURE(sCopy);
 | 
			
		||||
 | 
			
		||||
	REQUIRE(bCopy >= sCopy);
 | 
			
		||||
	REQUIRE(bMove <= sMove);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										127
									
								
								tests/edsl/edsl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								tests/edsl/edsl.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::arg;
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
static int counterDo, counterThen, counterDone;
 | 
			
		||||
 | 
			
		||||
struct Do { void operator()() { ++counterDo; } };
 | 
			
		||||
struct Then { void operator()() { ++counterThen; } };
 | 
			
		||||
struct Done { void operator()() { ++counterDone; } };
 | 
			
		||||
 | 
			
		||||
struct Produce0 { int operator()(int x) { return x+1; } };
 | 
			
		||||
struct Produce1 { int operator()(int x) { return x-2; } };
 | 
			
		||||
struct Consume { int operator()(int x, int y) { return x*y; } };
 | 
			
		||||
 | 
			
		||||
// TODO? avoid copies so it is truly stateful
 | 
			
		||||
struct Generate { int value; int operator()(int b) { return ++value+b; } };
 | 
			
		||||
struct Transform0 { int operator()(int x) { return x+1; } };
 | 
			
		||||
struct Transform1 { int operator()(int x) { return x-2; } };
 | 
			
		||||
struct Produce { int operator()(int x, int y) { return x*y; } };
 | 
			
		||||
struct Select {
 | 
			
		||||
	int mod;
 | 
			
		||||
	int operator()(int a, int b) { if(a%mod == b%mod) return std::min(a, b); return (a%mod > b%mod)? a : b; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl") {
 | 
			
		||||
	auto aDo    = makeOperand<Do>();
 | 
			
		||||
	auto aThen  = makeOperand<Then>();
 | 
			
		||||
	auto aDone  = makeOperand<Done>();
 | 
			
		||||
 | 
			
		||||
	auto aProduce0  = makeOperand<Produce0>();
 | 
			
		||||
	auto aProduce1  = makeOperand<Produce1>();
 | 
			
		||||
	auto aConsume   = makeOperand<Consume>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = aDo & (5*aThen) & aDone;
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::Serial, Do, alsk::S<alsk::Farm, Then>, Done>;
 | 
			
		||||
	using L0 = alsk::L<alsk::Serial, void(), void(), alsk::L<alsk::Farm, void(), void()>, void()>;
 | 
			
		||||
 | 
			
		||||
	auto e1 = 5*(aDo, 2*aThen, aDone);
 | 
			
		||||
	using E1 = decltype(e1);
 | 
			
		||||
	using S1 = alsk::S<alsk::Farm, alsk::S<alsk::Serial, Do, alsk::S<alsk::Farm, Then>, Done>>;
 | 
			
		||||
	using L1 = alsk::L<alsk::Farm, void(), alsk::L<alsk::Serial, void(), void(), alsk::L<alsk::Farm, void(), void()>, void()>>;
 | 
			
		||||
 | 
			
		||||
	auto e2 = link<R<2>(int)>(
 | 
			
		||||
		link<int(P<0>)>(aProduce0),
 | 
			
		||||
		link<int(P<0>)>(aProduce1),
 | 
			
		||||
		link<int(R<1>, R<0>)>(aConsume)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, void()>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, void()>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Linking") {
 | 
			
		||||
		{
 | 
			
		||||
			auto f2 = implement<alsk::exec::Sequential>(e2);
 | 
			
		||||
 | 
			
		||||
			REQUIRE(f2(0) == -2);
 | 
			
		||||
			REQUIRE(f2(2) == 0);
 | 
			
		||||
			REQUIRE(f2(5) == 18);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
		auto f0 = implement<alsk::exec::Sequential>(e0);
 | 
			
		||||
 | 
			
		||||
		REQUIRE(f0.skeleton.task<1>().n == 5);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Check run") {
 | 
			
		||||
		{
 | 
			
		||||
			auto f0 = implement<alsk::exec::Sequential>(e0);
 | 
			
		||||
 | 
			
		||||
			counterDo = counterThen = counterDone = 0;
 | 
			
		||||
			f0();
 | 
			
		||||
 | 
			
		||||
			REQUIRE(counterDo == 1);
 | 
			
		||||
			REQUIRE(counterThen == 5);
 | 
			
		||||
			REQUIRE(counterDone == 1);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			auto f1 = implement<alsk::exec::Sequential>(e1);
 | 
			
		||||
 | 
			
		||||
			counterDo = counterThen = counterDone = 0;
 | 
			
		||||
			f1();
 | 
			
		||||
 | 
			
		||||
			REQUIRE(counterDo == 5);
 | 
			
		||||
			REQUIRE(counterThen == 10);
 | 
			
		||||
			REQUIRE(counterDone == 5);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Complex case") {
 | 
			
		||||
		auto generate = makeOperand<Generate>();
 | 
			
		||||
		auto transform0 = makeOperand<Transform0>();
 | 
			
		||||
		auto transform1 = makeOperand<Transform1>();
 | 
			
		||||
		auto produce = makeOperand<Produce>();
 | 
			
		||||
		auto select = makeOperand<int(int, int), Select>();
 | 
			
		||||
 | 
			
		||||
		auto innerTask = link<R<3>(int)>(
 | 
			
		||||
			link<int(P<0>)>(generate),
 | 
			
		||||
			link<int(R<0>)>(transform0),
 | 
			
		||||
			link<int(R<0>)>(transform1),
 | 
			
		||||
			link<int(R<2>, R<1>)>(produce)
 | 
			
		||||
		);
 | 
			
		||||
		auto task = link<int(int)>(10 * link<R<3>(P<0>)>(innerTask)) ->* select;
 | 
			
		||||
 | 
			
		||||
		auto f = implement<alsk::exec::Sequential>(task);
 | 
			
		||||
		f.skeleton.select.mod = 5;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(f(4) == 18);
 | 
			
		||||
		REQUIRE(f(5) == 28);
 | 
			
		||||
		REQUIRE(f(6) == 40);
 | 
			
		||||
		REQUIRE(f(7) == 54);
 | 
			
		||||
		REQUIRE(f(8) == 70);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								tests/edsl/op/farm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								tests/edsl/op/farm.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Do { void operator()() { std::puts("Do"); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::Farm") {
 | 
			
		||||
	auto aDo    = makeOperand<Do>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = *aDo;
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::Farm, Do>;
 | 
			
		||||
	using L0 = alsk::L<alsk::Farm, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	auto e1 = 5*aDo;
 | 
			
		||||
	using E1 = decltype(e1);
 | 
			
		||||
	using S1 = alsk::S<alsk::Farm, Do>;
 | 
			
		||||
	using L1 = alsk::L<alsk::Farm, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	auto e2 = aDo*3;
 | 
			
		||||
	using E2 = decltype(e2);
 | 
			
		||||
	using S2 = alsk::S<alsk::Farm, Do>;
 | 
			
		||||
	using L2 = alsk::L<alsk::Farm, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	auto e3 = farm(aDo, 3);
 | 
			
		||||
	using E3 = decltype(e3);
 | 
			
		||||
	using S3 = alsk::S<alsk::Farm, Do>;
 | 
			
		||||
	using L3 = alsk::L<alsk::Farm, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E2::Struct, S2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Links, L2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E3::Struct, S3>{});
 | 
			
		||||
		REQUIRE(std::is_same<E3::Links, L3>{});
 | 
			
		||||
		REQUIRE(std::is_same<E3::Signature, void()>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
		auto f0 = implement<alsk::exec::Sequential>(e0);
 | 
			
		||||
		REQUIRE(f0.skeleton.n == 0);
 | 
			
		||||
 | 
			
		||||
		auto f1 = implement<alsk::exec::Sequential>(e1);
 | 
			
		||||
		REQUIRE(f1.skeleton.n == 5);
 | 
			
		||||
 | 
			
		||||
		auto f2 = implement<alsk::exec::Sequential>(e2);
 | 
			
		||||
		REQUIRE(f2.skeleton.n == 3);
 | 
			
		||||
 | 
			
		||||
		auto f3 = implement<alsk::exec::Sequential>(e3);
 | 
			
		||||
		REQUIRE(f3.skeleton.n == 3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								tests/edsl/op/farmsel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								tests/edsl/op/farmsel.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Generate { int operator()() { return 0; } };
 | 
			
		||||
struct Select { int operator()(int a, int b) { return std::max(a, b); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::FarmSel") {
 | 
			
		||||
	auto generate = makeOperand<int(), Generate>();
 | 
			
		||||
	auto select = makeOperand<int(int, int), Select>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = (10 * generate) ->* select;
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::FarmSel, Generate, Select>;
 | 
			
		||||
	using L0 = alsk::L<alsk::FarmSel, int(), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	auto e1 = link<void(int)>(*generate) ->* select;
 | 
			
		||||
	using E1 = decltype(e1);
 | 
			
		||||
	using S1 = alsk::S<alsk::FarmSel, Generate, Select>;
 | 
			
		||||
	using L1 = alsk::L<alsk::FarmSel, int(int), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	auto e2 = farm(generate).select(select);
 | 
			
		||||
	using E2 = decltype(e2);
 | 
			
		||||
	using S2 = alsk::S<alsk::FarmSel, Generate, Select>;
 | 
			
		||||
	using L2 = alsk::L<alsk::FarmSel, int(), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, int()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, int(int)>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E2::Struct, S2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Links, L2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Signature, int()>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
		auto f0 = implement<alsk::exec::DynamicPool>(e0);
 | 
			
		||||
		REQUIRE(f0.skeleton.n == 10);
 | 
			
		||||
 | 
			
		||||
		auto f1 = implement<alsk::exec::DynamicPool>(e1);
 | 
			
		||||
		REQUIRE(f1.skeleton.n == 0);
 | 
			
		||||
 | 
			
		||||
		auto f2 = implement<alsk::exec::DynamicPool>(e2);
 | 
			
		||||
		REQUIRE(f2.skeleton.n == 0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								tests/edsl/op/itersel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								tests/edsl/op/itersel.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Generate { int operator()() { return 0; } };
 | 
			
		||||
struct Select { int operator()(int a, int b) { return std::max(a, b); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::IterSel") {
 | 
			
		||||
	auto generate = makeOperand<int(), Generate>();
 | 
			
		||||
	auto select = makeOperand<int(int, int), Select>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = iter(generate, 10).select(select);
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::IterSel, Generate, Select>;
 | 
			
		||||
	using L0 = alsk::L<alsk::IterSel, int(), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	auto e1 = &(link<void(int)>(*generate) ->* select);
 | 
			
		||||
	using E1 = decltype(e1);
 | 
			
		||||
	using S1 = alsk::S<alsk::IterSel, Generate, Select>;
 | 
			
		||||
	using L1 = alsk::L<alsk::IterSel, int(int), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	auto e2 = seq(link<void(int)>(*generate) ->* select);
 | 
			
		||||
	using E2 = decltype(e2);
 | 
			
		||||
	using S2 = alsk::S<alsk::IterSel, Generate, Select>;
 | 
			
		||||
	using L2 = alsk::L<alsk::IterSel, int(int), int(), int(int, int)>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, int()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, int(int)>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E2::Struct, S2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Links, L2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Signature, int(int)>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
		auto f0 = implement<alsk::exec::DynamicPool>(e0);
 | 
			
		||||
		REQUIRE(f0.skeleton.n == 10);
 | 
			
		||||
 | 
			
		||||
		auto f1 = implement<alsk::exec::DynamicPool>(e1);
 | 
			
		||||
		REQUIRE(f1.skeleton.n == 0);
 | 
			
		||||
 | 
			
		||||
		auto f2 = implement<alsk::exec::DynamicPool>(e2);
 | 
			
		||||
		REQUIRE(f2.skeleton.n == 0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								tests/edsl/op/loop.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tests/edsl/op/loop.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Do { void operator()() { std::puts("Do"); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::Loop") {
 | 
			
		||||
	auto aDo    = makeOperand<Do>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = loop(aDo);
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::Loop, Do>;
 | 
			
		||||
	using L0 = alsk::L<alsk::Loop, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	auto e1 = seq(5*aDo);
 | 
			
		||||
	using E1 = decltype(e1);
 | 
			
		||||
	using S1 = alsk::S<alsk::Loop, Do>;
 | 
			
		||||
	using L1 = alsk::L<alsk::Loop, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	auto e2 = &(aDo*3);
 | 
			
		||||
	using E2 = decltype(e2);
 | 
			
		||||
	using S2 = alsk::S<alsk::Loop, Do>;
 | 
			
		||||
	using L2 = alsk::L<alsk::Loop, void(), void()>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E2::Struct, S2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Links, L2>{});
 | 
			
		||||
		REQUIRE(std::is_same<E2::Signature, void()>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
		auto f0 = implement<alsk::exec::Sequential>(e0);
 | 
			
		||||
		REQUIRE(f0.skeleton.n == 0);
 | 
			
		||||
 | 
			
		||||
		auto f1 = implement<alsk::exec::Sequential>(e1);
 | 
			
		||||
		REQUIRE(f1.skeleton.n == 5);
 | 
			
		||||
 | 
			
		||||
		auto f2 = implement<alsk::exec::Sequential>(e2);
 | 
			
		||||
		REQUIRE(f2.skeleton.n == 3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								tests/edsl/op/operand.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								tests/edsl/op/operand.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct A { void operator()() {} };
 | 
			
		||||
struct B { int operator()(float) { return {}; } };
 | 
			
		||||
 | 
			
		||||
void f() {}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::Operand") {
 | 
			
		||||
	SECTION("from function-object") {
 | 
			
		||||
		{
 | 
			
		||||
			auto x = makeOperand<A>();
 | 
			
		||||
			using X = decltype(x);
 | 
			
		||||
 | 
			
		||||
			REQUIRE(std::is_same<X::Struct, A>{});
 | 
			
		||||
			REQUIRE(std::is_same<X::Links, void()>{});
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			auto x = makeOperand<int(alsk::arg::P<0>), B>();
 | 
			
		||||
			using X = decltype(x);
 | 
			
		||||
 | 
			
		||||
			REQUIRE(std::is_same<X::Struct, B>{});
 | 
			
		||||
			REQUIRE(std::is_same<X::Links, int(alsk::arg::P<0>)>{});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("from function") {
 | 
			
		||||
		{
 | 
			
		||||
			auto x = alskMakeOperand(f);
 | 
			
		||||
			using X = decltype(x);
 | 
			
		||||
 | 
			
		||||
			REQUIRE(std::is_same<X::Struct, Fn<void(&)(), f>>{});
 | 
			
		||||
			REQUIRE(std::is_same<X::Links, void()>{});
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			using Signature = int const&(&)(int const&, int const&);
 | 
			
		||||
			auto x = makeOperand<Signature, std::min<int>>();
 | 
			
		||||
			using X = decltype(x);
 | 
			
		||||
 | 
			
		||||
			REQUIRE(std::is_same<X::Struct, Fn<Signature, std::min<int>>>{});
 | 
			
		||||
			REQUIRE(std::is_same<X::Links, int const&(int const&, int const&)>{});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								tests/edsl/op/serial.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/edsl/op/serial.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Do { void operator()() { std::puts("Do"); } };
 | 
			
		||||
struct Then { void operator()() { std::puts("Then"); } };
 | 
			
		||||
struct Done { void operator()() { std::puts("Done"); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::Serial") {
 | 
			
		||||
	auto aDo    = makeOperand<Do>();
 | 
			
		||||
	auto aThen  = makeOperand<Then>();
 | 
			
		||||
	auto aDone  = makeOperand<Done>();
 | 
			
		||||
 | 
			
		||||
	using E0 = decltype(aDo & aThen);
 | 
			
		||||
	using E1 = decltype(aDo, aThen, aDone);
 | 
			
		||||
 | 
			
		||||
	using S0 = alsk::S<alsk::Serial, Do, Then>;
 | 
			
		||||
	using S1 = alsk::S<alsk::Serial, Do, Then, Done>;
 | 
			
		||||
 | 
			
		||||
	using L0 = alsk::L<alsk::Serial, void(), void(), void()>;
 | 
			
		||||
	using L1 = alsk::L<alsk::Serial, void(), void(), void(), void()>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, void()>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Signature, void()>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Struct, S1>{});
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E1::Links, L1>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("Setup") {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								tests/edsl/op/while.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/edsl/op/while.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::edsl;
 | 
			
		||||
 | 
			
		||||
struct Pred { int n; bool operator()() { return --n; } };
 | 
			
		||||
struct Do { void operator()() { std::puts("Do"); } };
 | 
			
		||||
 | 
			
		||||
TEST_CASE("edsl::While") {
 | 
			
		||||
	auto aPred  = makeOperand<bool(), Pred>();
 | 
			
		||||
	auto aDo    = makeOperand<Do>();
 | 
			
		||||
 | 
			
		||||
	auto e0 = while_(aPred).do_(aDo);
 | 
			
		||||
	using E0 = decltype(e0);
 | 
			
		||||
	using S0 = alsk::S<alsk::While, Pred, Do>;
 | 
			
		||||
	using L0 = alsk::L<alsk::While, void(), bool(), void()>;
 | 
			
		||||
 | 
			
		||||
	SECTION("Construction") {
 | 
			
		||||
		REQUIRE(std::is_same<E0::Struct, S0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Links, L0>{});
 | 
			
		||||
		REQUIRE(std::is_same<E0::Signature, void()>{});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								tests/executor/base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								tests/executor/base.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
TEST_CASE("ExecutorBase") {
 | 
			
		||||
	alsk::exec::ExecutorBase e;
 | 
			
		||||
	SECTION("Repeatability") {
 | 
			
		||||
		auto& r = e.repeatability;
 | 
			
		||||
		auto const& cl = r.coresList;
 | 
			
		||||
 | 
			
		||||
		SECTION("upTo") {
 | 
			
		||||
			SECTION("disabled") {
 | 
			
		||||
				r.upTo(0);
 | 
			
		||||
				REQUIRE(cl.empty());
 | 
			
		||||
 | 
			
		||||
				r.upTo(1);
 | 
			
		||||
				REQUIRE(cl.empty());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SECTION("enabled") {
 | 
			
		||||
				for(std::size_t k = 10; k < 20; ++k) {
 | 
			
		||||
					r.upTo(k);
 | 
			
		||||
					REQUIRE(cl.size() == k-1);
 | 
			
		||||
					for(std::size_t i = 0; i < cl.size(); ++i)
 | 
			
		||||
						REQUIRE(cl[i] == 2+i);
 | 
			
		||||
 | 
			
		||||
					for(std::size_t m = 3; m < 10; ++m) {
 | 
			
		||||
						r.upTo(k, m);
 | 
			
		||||
						REQUIRE(cl.size() == k-m+1);
 | 
			
		||||
						for(std::size_t i = 0; i < cl.size(); ++i)
 | 
			
		||||
							REQUIRE(cl[i] == m+i);
 | 
			
		||||
 | 
			
		||||
						for(std::size_t s = 2; s < 5; ++s) {
 | 
			
		||||
							r.upTo(k, m, s);
 | 
			
		||||
							REQUIRE(cl.size() == (k-m+1+s-1)/s);
 | 
			
		||||
							for(std::size_t i = 0; i < cl.size(); ++i)
 | 
			
		||||
								REQUIRE(cl[i] == m+i*s);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										161
									
								
								tests/executor/common.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								tests/executor/common.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <tmp/debug.h>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
std::atomic_ullong CallCounterV::count{};
 | 
			
		||||
std::atomic_ullong CallCounterII::count{};
 | 
			
		||||
 | 
			
		||||
namespace expar {
 | 
			
		||||
 | 
			
		||||
auto buildTestFunction() {
 | 
			
		||||
	auto callCounterv = alsk::edsl::makeOperand<int(), CallCounterV>();
 | 
			
		||||
	auto callCounterii = alsk::edsl::makeOperand<int(int, int), CallCounterII>();
 | 
			
		||||
 | 
			
		||||
	auto loop     = seq(3*callCounterv);
 | 
			
		||||
	auto serial   = link<R<0>()>(callCounterv, loop);
 | 
			
		||||
	auto itersel  = (callCounterv, &link<int(R<0>)>(5*link<R<0>(int)>(serial)) ->* callCounterii);
 | 
			
		||||
	auto farmsel  = link<int()>(7*link<R<1>()>(itersel, callCounterv)) ->* callCounterii;
 | 
			
		||||
	auto farm     = 11*farmsel;
 | 
			
		||||
 | 
			
		||||
	return farm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr auto countV() { return 11 * 7 * (1 + 5 * (1 + 3) + 1); }
 | 
			
		||||
constexpr auto countII() { return 11 * ((7 - 1) + 7 * 5); }
 | 
			
		||||
 | 
			
		||||
constexpr auto maxCores = 11*7 * 64;
 | 
			
		||||
constexpr std::array<decltype(maxCores), 8> coresList{1, 2, 3, 7, 11*7-1, 11*7, 11*7+1, maxCores};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace exacc {
 | 
			
		||||
 | 
			
		||||
auto buildTestFunction() {
 | 
			
		||||
	auto callCounterv = alsk::edsl::makeOperand<int(), CallCounterV>();
 | 
			
		||||
	auto callCounterii = alsk::edsl::makeOperand<int(int, int), CallCounterII>();
 | 
			
		||||
 | 
			
		||||
	auto loop     = seq(3*callCounterv);
 | 
			
		||||
	auto serial   = link<R<0>()>(callCounterv, loop);
 | 
			
		||||
	auto itersel  = (callCounterv, &link<int(R<0>)>(5*link<R<0>(int)>(serial)) ->* callCounterii);
 | 
			
		||||
	auto farm     = link<R<1>()>(7*itersel, callCounterv);
 | 
			
		||||
	auto farmsel  = link<int()>(11*farm) ->* callCounterii;
 | 
			
		||||
 | 
			
		||||
	return farmsel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr auto countV() { return 11 * (7 * (1 + 5 * (1 + 3)) + 1); }
 | 
			
		||||
constexpr auto countII() { return (11-1) + 11 * 7 * 5; }
 | 
			
		||||
 | 
			
		||||
constexpr auto maxCores = 11*7 * 64;
 | 
			
		||||
constexpr std::array<decltype(maxCores), 8> coresList{1, 2, 3, 7, 11*7-1, 11*7, 11*7+1, maxCores};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace repeatability {
 | 
			
		||||
 | 
			
		||||
using PRNG = std::mt19937;
 | 
			
		||||
int task(PRNG& rng, std::size_t) {
 | 
			
		||||
	std::uniform_int_distribution<int> dist(-100, 100);
 | 
			
		||||
 | 
			
		||||
	int a = dist(rng);
 | 
			
		||||
	std::this_thread::sleep_for(std::chrono::milliseconds(0));
 | 
			
		||||
	int b = dist(rng);
 | 
			
		||||
 | 
			
		||||
	return a - b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sel(int a, int b) { return a + b; }
 | 
			
		||||
 | 
			
		||||
auto buildTestFunction() {
 | 
			
		||||
	auto etask  = alsk::edsl::makeOperand<int(RNG, CtxId), FN(task)>();
 | 
			
		||||
	auto esel   = alsk::edsl::makeOperand<int(int, int), FN(sel)>();
 | 
			
		||||
 | 
			
		||||
	auto loop     = seq(3*etask);
 | 
			
		||||
	auto serial   = link<R<0>()>(etask, (2*loop));
 | 
			
		||||
	auto farmsel  = link<int()>(5*serial) ->* esel;
 | 
			
		||||
 | 
			
		||||
	return link<R<1>()>(farmsel, farmsel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
 | 
			
		||||
using Executors = std::tuple<
 | 
			
		||||
		exec::DynamicPool<void>,
 | 
			
		||||
		exec::FirstLevelEqui<void>,
 | 
			
		||||
		exec::FirstLevelGreedy<void>,
 | 
			
		||||
		exec::FirstLevelNoOpti<void>,
 | 
			
		||||
		exec::Sequential<void>,
 | 
			
		||||
		exec::StaticPool<void>,
 | 
			
		||||
		exec::StaticPoolId<void>,
 | 
			
		||||
		exec::StaticThread<void>
 | 
			
		||||
>;
 | 
			
		||||
TEMPLATE_LIST_TEST_CASE("Executors", "[executors]", Executors) {
 | 
			
		||||
	CAPTURE(tmp::typeName<TestType>());
 | 
			
		||||
 | 
			
		||||
	SECTION("executeParallel") {
 | 
			
		||||
		using namespace expar;
 | 
			
		||||
 | 
			
		||||
		auto e = buildTestFunction();
 | 
			
		||||
		for(auto cores: coresList) {
 | 
			
		||||
			auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
 | 
			
		||||
			f.executor.cores = cores;
 | 
			
		||||
 | 
			
		||||
			CallCounterV::count = 0;
 | 
			
		||||
			CallCounterII::count = 0;
 | 
			
		||||
 | 
			
		||||
			f();
 | 
			
		||||
 | 
			
		||||
			REQUIRE(CallCounterV::count == countV());
 | 
			
		||||
			REQUIRE(CallCounterII::count == countII());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("executeParallelAccumulate") {
 | 
			
		||||
		using namespace exacc;
 | 
			
		||||
 | 
			
		||||
		auto e = buildTestFunction();
 | 
			
		||||
		for(auto cores: coresList) {
 | 
			
		||||
			auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
 | 
			
		||||
			f.executor.cores = cores;
 | 
			
		||||
 | 
			
		||||
			CallCounterV::count = 0;
 | 
			
		||||
			CallCounterII::count = 0;
 | 
			
		||||
 | 
			
		||||
			f();
 | 
			
		||||
 | 
			
		||||
			REQUIRE(CallCounterV::count == countV());
 | 
			
		||||
			REQUIRE(CallCounterII::count == countII());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEMPLATE_LIST_TEST_CASE("Repeatability", "[executors][repeatability]", Executors) {
 | 
			
		||||
	using namespace repeatability;
 | 
			
		||||
 | 
			
		||||
	CAPTURE(tmp::typeName<TestType>());
 | 
			
		||||
 | 
			
		||||
	auto e = buildTestFunction();
 | 
			
		||||
	for(std::size_t upTo: {2, 3, 4, 5, 6, 7, 8}) {
 | 
			
		||||
		CAPTURE(upTo);
 | 
			
		||||
 | 
			
		||||
		auto f = edsl::implement<GetExecutor<TestType>::template Template>(e);
 | 
			
		||||
		f.executor.repeatability.upTo(upTo);
 | 
			
		||||
 | 
			
		||||
		f.executor.cores = 1;
 | 
			
		||||
 | 
			
		||||
		auto expected = f();
 | 
			
		||||
		f.state.context.reset();
 | 
			
		||||
 | 
			
		||||
		for(std::size_t cores = 2; cores <= upTo; ++cores) {
 | 
			
		||||
			CAPTURE(cores);
 | 
			
		||||
 | 
			
		||||
			f.executor.cores = cores;
 | 
			
		||||
 | 
			
		||||
			REQUIRE(f() == expected);
 | 
			
		||||
			f.state.context.reset();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								tests/executor/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/executor/common.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk::arg;
 | 
			
		||||
using alsk::edsl::link;
 | 
			
		||||
 | 
			
		||||
template<typename> struct GetExecutor;
 | 
			
		||||
template<template<typename> class TT, typename Arg>
 | 
			
		||||
struct GetExecutor<TT<Arg>> {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	using Template = TT<T>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CallCounterV {
 | 
			
		||||
	static std::atomic_ullong count;
 | 
			
		||||
	int operator()() { ++count; return {}; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CallCounterII {
 | 
			
		||||
	static std::atomic_ullong count;
 | 
			
		||||
	int operator()(int, int) { ++count; return {}; }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/executor/dynamicpool.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/executor/dynamicpool.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("DynamicPool") {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/executor/firstlevel/equi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/executor/firstlevel/equi.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include "../common.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("FirstLevelEqui") {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/executor/firstlevel/greedy.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/executor/firstlevel/greedy.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include "../common.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("FirstLevelGreedy") {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/executor/firstlevel/noopti.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/executor/firstlevel/noopti.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include "../common.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("FirstLevelNoOpti") {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/executor/sequential.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/executor/sequential.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Sequential") {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								tests/farmsel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								tests/farmsel.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
#include <random>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("FarmSel") {
 | 
			
		||||
	constexpr std::size_t n = 1024;
 | 
			
		||||
 | 
			
		||||
	SECTION("basic test") {
 | 
			
		||||
		using Data = int;
 | 
			
		||||
 | 
			
		||||
		using Task = std::function<Data()>;
 | 
			
		||||
		using Accu = std::function<Data(Data const&, Data const&)>;
 | 
			
		||||
 | 
			
		||||
		std::atomic_size_t countTask, countAccu;
 | 
			
		||||
 | 
			
		||||
		Task task = [&]{
 | 
			
		||||
			++countTask;
 | 
			
		||||
			return 42;
 | 
			
		||||
		};
 | 
			
		||||
		Accu accu = [&](Data const& a, Data const& b) {
 | 
			
		||||
			++countAccu;
 | 
			
		||||
			return std::min(a, b);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		using Skel = decltype(getSkeleton((*edsl::makeOperand<Data(), Task>()) ->* edsl::makeOperand<Data(Data, Data), Accu>()));
 | 
			
		||||
 | 
			
		||||
		auto f = implement<exec::FirstLevelEqui, Skel>();
 | 
			
		||||
		f.skeleton.n      = n;
 | 
			
		||||
		f.skeleton.task   = task;
 | 
			
		||||
		f.skeleton.select = accu;
 | 
			
		||||
 | 
			
		||||
		countTask = countAccu = 0;
 | 
			
		||||
 | 
			
		||||
		SECTION("cores = 1") {
 | 
			
		||||
			f.executor.cores = 1;
 | 
			
		||||
 | 
			
		||||
			Data d = f();
 | 
			
		||||
			REQUIRE(d == 42);
 | 
			
		||||
			REQUIRE(countTask == f.skeleton.n);
 | 
			
		||||
			REQUIRE(countAccu == f.skeleton.n-1);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SECTION("cores = 2") {
 | 
			
		||||
			f.executor.cores = 2;
 | 
			
		||||
 | 
			
		||||
			Data d = f();
 | 
			
		||||
			REQUIRE(d == 42);
 | 
			
		||||
			REQUIRE(countTask == f.skeleton.n);
 | 
			
		||||
			REQUIRE(countAccu == f.skeleton.n-1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("repeatability") {
 | 
			
		||||
		using Data  = std::tuple<int, std::string>;
 | 
			
		||||
		using RNG   = std::mt19937;
 | 
			
		||||
 | 
			
		||||
		using Task = std::function<Data(RNG&)>;
 | 
			
		||||
		using Accu = std::function<Data(Data const&, Data const&)>;
 | 
			
		||||
 | 
			
		||||
		std::atomic_size_t countTask, countAccu;
 | 
			
		||||
 | 
			
		||||
		Task task = [&](RNG& rng) {
 | 
			
		||||
			std::uniform_int_distribution<int> dist{0, 32};
 | 
			
		||||
			std::uniform_int_distribution<int> text{0, n*n};
 | 
			
		||||
			++countTask;
 | 
			
		||||
			return Data{dist(rng), std::to_string(text(rng))};
 | 
			
		||||
		};
 | 
			
		||||
		Accu accu = [&](Data const& a, Data const& b) {
 | 
			
		||||
			++countAccu;
 | 
			
		||||
			return std::get<0>(a) < std::get<0>(b)? a:b;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		using Struct  = S<FarmSel, Task, Accu>;
 | 
			
		||||
		using Links   = L<FarmSel, Data(), Data(arg::RNG), Data(Data, Data)>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		auto f = implement<exec::FirstLevelEqui, Skel>();
 | 
			
		||||
		f.skeleton.n      = n;
 | 
			
		||||
		f.skeleton.task   = task;
 | 
			
		||||
		f.skeleton.select = accu;
 | 
			
		||||
		f.executor.cores  = 1;
 | 
			
		||||
 | 
			
		||||
		Data expected = f();
 | 
			
		||||
 | 
			
		||||
		countTask = countAccu = 0;
 | 
			
		||||
 | 
			
		||||
		for(std::size_t k = 1; k <= 2; k *= 2) {
 | 
			
		||||
			SECTION("cores = "+std::to_string(k)) {
 | 
			
		||||
				f.executor.cores = k;
 | 
			
		||||
 | 
			
		||||
				f.state.context.reset();
 | 
			
		||||
				Data d = f();
 | 
			
		||||
				REQUIRE(std::get<0>(d) == std::get<0>(expected));
 | 
			
		||||
				REQUIRE(std::get<1>(d) == std::get<1>(expected));
 | 
			
		||||
				REQUIRE(countTask == f.skeleton.n);
 | 
			
		||||
				REQUIRE(countAccu == f.skeleton.n-1);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/main.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
#define CATCH_CONFIG_MAIN
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
							
								
								
									
										152
									
								
								tests/serial.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								tests/serial.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/alsk.h>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
using Vector = Measure<std::vector<int>>;
 | 
			
		||||
 | 
			
		||||
using Struct =
 | 
			
		||||
S<Serial,
 | 
			
		||||
	S<Serial, Mult, Mult, MultC<double>, Add>,
 | 
			
		||||
	MultC<double>,
 | 
			
		||||
	Sqrt,
 | 
			
		||||
	S<Serial, Add, Div>,
 | 
			
		||||
	S<Serial, MultC<double>, Add, Div>,
 | 
			
		||||
	Tupler
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using Links =
 | 
			
		||||
L<Serial, arg::R<5>(double, double, double),
 | 
			
		||||
	L<Serial, arg::R<3>(arg::P<0>, arg::P<1>, arg::P<2>), // a, b, c
 | 
			
		||||
		double(arg::P<1>, arg::P<1>), // b*b
 | 
			
		||||
		double(arg::P<0>, arg::P<2>), // a*c
 | 
			
		||||
		double(arg::R<1>),            // a*c*#
 | 
			
		||||
		double(arg::R<0>, arg::R<2>)  // b*b + a*c*# = D
 | 
			
		||||
	>,
 | 
			
		||||
	double(arg::P<0>),              // a*#
 | 
			
		||||
	double(arg::R<0>),              // sqrt(D)
 | 
			
		||||
	L<Serial, arg::R<1>(arg::P<1>, arg::R<2>, arg::R<1>), // b, sqrt(D), a*#
 | 
			
		||||
		double(arg::P<0>, arg::P<1>), // +
 | 
			
		||||
		double(arg::R<0>, arg::P<2>)  // ^/(a*#)
 | 
			
		||||
	>,
 | 
			
		||||
	L<Serial, arg::R<2>(arg::P<1>, arg::R<2>, arg::R<1>), // b, sqrt(D), a*#
 | 
			
		||||
		double(arg::P<1>),            // sqrt(D)*#
 | 
			
		||||
		double(arg::R<0>, arg::P<0>), // ^+b
 | 
			
		||||
		double(arg::R<1>, arg::P<2>)  // ^/(a*#)
 | 
			
		||||
	>,
 | 
			
		||||
	std::tuple<double, double>(arg::R<3>, arg::R<4>)
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using Solver = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
constexpr std::initializer_list<int> benchVec1{5, 2, 3, 7, 8, 9, 1, 2, 7, 6, 3, 2, 7};
 | 
			
		||||
constexpr std::initializer_list<int> benchVec2{2, 2, 3, 5, 2, 1, 1, 4, 7, 9, 2, 3, 5, 6, 1};
 | 
			
		||||
 | 
			
		||||
using MultiplyByV = MultiplyBy<Vector>;
 | 
			
		||||
using ProcessV = Process<Vector>;
 | 
			
		||||
using SumV = Sum<Vector>;
 | 
			
		||||
using ProdVectV = ProdVect<Vector>;
 | 
			
		||||
 | 
			
		||||
using CMTestStruct = S<Serial, MultiplyByV, MultiplyByV, ProcessV, ProcessV, SumV, ProdVectV>;
 | 
			
		||||
using CMTestLinks =
 | 
			
		||||
L<Serial, arg::R<4>(int, int, int, int&),
 | 
			
		||||
	int(arg::P<0>), int(arg::P<1>),
 | 
			
		||||
	Vector(arg::P<2>, arg::R<0>), Vector(arg::P<2>, arg::R<1>),
 | 
			
		||||
	Vector(arg::R<2> const&, arg::R<3> const&),
 | 
			
		||||
	void(arg::P<3>, arg::R<2> const&, arg::R<3> const&)
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using CMTest = BuildSkeletonT<CMTestStruct, CMTestLinks>;
 | 
			
		||||
 | 
			
		||||
decltype(auto) cmTest(int a, int b, int n, int& r) {
 | 
			
		||||
	decltype(auto) r0 = MultiplyByV{Vector::value_type{benchVec1}}(a);
 | 
			
		||||
	decltype(auto) r1 = MultiplyByV{Vector::value_type{benchVec2}}(b);
 | 
			
		||||
	decltype(auto) r2 = ProcessV{}(n, r0);
 | 
			
		||||
	decltype(auto) r3 = ProcessV{}(n, r1);
 | 
			
		||||
	decltype(auto) r4 = SumV{}(r2, r3);
 | 
			
		||||
	ProdVectV{}(r, r2, r3);
 | 
			
		||||
	return r4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Serial") {
 | 
			
		||||
	SECTION("basic test") {
 | 
			
		||||
		using F0 = std::function<int()>;
 | 
			
		||||
		using FN = std::function<int(int)>;
 | 
			
		||||
		using FX = std::function<int(int, int)>;
 | 
			
		||||
 | 
			
		||||
		std::size_t count;
 | 
			
		||||
 | 
			
		||||
		F0 f0 = [&]{ ++count; return 0; };
 | 
			
		||||
		FN f1 = [&](int v) { ++count; return v+1; };
 | 
			
		||||
		FN f2 = [&](int v) { ++count; return v*2; };
 | 
			
		||||
		FX f3 = [&](int v, int x) { ++count; return v<<x; };
 | 
			
		||||
 | 
			
		||||
		using Struct  = S<Serial, F0, S<Serial, FN, FN>, FX>;
 | 
			
		||||
		using Links   = L<Serial, arg::R<2>(int), int(), L<Serial, arg::R<1>(arg::R<0>), int(arg::P<0>), int(arg::R<0>)>, int(arg::R<1>, arg::P<0>)>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		auto f = implement<exec::FirstLevelEqui, Skel>();
 | 
			
		||||
		f.skeleton.task<0>() = f0;
 | 
			
		||||
		f.skeleton.task<1>().task<0>() = f1;
 | 
			
		||||
		f.skeleton.task<1>().task<1>() = f2;
 | 
			
		||||
		f.skeleton.task<2>() = f3;
 | 
			
		||||
 | 
			
		||||
		count = 0;
 | 
			
		||||
		REQUIRE(f(3) == 16);
 | 
			
		||||
		REQUIRE(count == 4);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("serial") {
 | 
			
		||||
		auto solver = implement<exec::StaticPool, Solver>();
 | 
			
		||||
		solver.skeleton.task<0>().task<2>().m = -4;
 | 
			
		||||
		solver.skeleton.task<1>().m = -2;
 | 
			
		||||
		solver.skeleton.task<4>().task<0>().m = -1;
 | 
			
		||||
 | 
			
		||||
		double x0 = -2.63;
 | 
			
		||||
		double x1 = 3.77;
 | 
			
		||||
 | 
			
		||||
		double a = 3.7;
 | 
			
		||||
		double b = -a*(x0+x1);
 | 
			
		||||
		double c = a*x0*x1;
 | 
			
		||||
 | 
			
		||||
		auto sol = solver(a, b, c);
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::get<0>(sol) == Approx{x0});
 | 
			
		||||
		REQUIRE(std::get<1>(sol) == Approx{x1});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("copy/moves") {
 | 
			
		||||
		int a{500}, b{100}, n{1'000}, r;
 | 
			
		||||
		int cpBase, mvBase, cpSkel, mvSkel;
 | 
			
		||||
 | 
			
		||||
		_copy = _move = 0;
 | 
			
		||||
		cmTest(a, b, n, r);
 | 
			
		||||
		cpBase = _copy;
 | 
			
		||||
		mvBase = _move;
 | 
			
		||||
 | 
			
		||||
		std::printf("[base] copy: %zu, move: %zu\n", _copy, _move);
 | 
			
		||||
 | 
			
		||||
		_copy = _move = 0;
 | 
			
		||||
 | 
			
		||||
		auto cmTestSkel = implement<exec::Sequential, CMTest>();
 | 
			
		||||
		// cmTestSkel(a, b);
 | 
			
		||||
		cmTestSkel.skeleton.task<0>() = MultiplyByV{Vector::value_type{benchVec1}};
 | 
			
		||||
		cmTestSkel.skeleton.task<1>() = MultiplyByV{Vector::value_type{benchVec2}};
 | 
			
		||||
 | 
			
		||||
		cmTestSkel(a, b, n, r);
 | 
			
		||||
 | 
			
		||||
		cpSkel = _copy;
 | 
			
		||||
		mvSkel = _move;
 | 
			
		||||
 | 
			
		||||
		std::printf("[skel] copy: %zu, move: %zu\n", _copy, _move);
 | 
			
		||||
 | 
			
		||||
		REQUIRE(cpBase >= cpSkel);
 | 
			
		||||
		REQUIRE(mvBase <= mvSkel);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										264
									
								
								tests/skeleton.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								tests/skeleton.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,264 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/skeleton/skeleton.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
using tmp::Pack;
 | 
			
		||||
 | 
			
		||||
struct Int {
 | 
			
		||||
	int v;
 | 
			
		||||
	Int(int v): v{v} {}
 | 
			
		||||
	operator int() const { return v; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct A: Int {};
 | 
			
		||||
struct B: Int {};
 | 
			
		||||
struct C: Int {};
 | 
			
		||||
struct D: Int {};
 | 
			
		||||
struct E: Int {};
 | 
			
		||||
struct F: Int {};
 | 
			
		||||
struct G: Int {};
 | 
			
		||||
struct H: Int {};
 | 
			
		||||
struct I: Int {};
 | 
			
		||||
 | 
			
		||||
template<typename R>
 | 
			
		||||
struct Unary {
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	R operator()(T a) { return{a+1}; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename R>
 | 
			
		||||
struct Binary {
 | 
			
		||||
	template<typename T, typename U>
 | 
			
		||||
	R operator()(T a, U b) { return{a+b}; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct Binary<void> {
 | 
			
		||||
	template<typename T, typename U>
 | 
			
		||||
	void operator()(T, U) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using S_ =
 | 
			
		||||
S<Serial,
 | 
			
		||||
	S<Serial, Unary<D>, Binary<E>>,
 | 
			
		||||
	Unary<F>,
 | 
			
		||||
	S<Serial,
 | 
			
		||||
		Unary<G>,
 | 
			
		||||
		S<Serial, Unary<H>, Binary<void>>,
 | 
			
		||||
		Unary<I>
 | 
			
		||||
	>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using L1 =
 | 
			
		||||
L<Serial, arg::R<1>(arg::P<1>, arg::P<2>),
 | 
			
		||||
	D(arg::P<1>),
 | 
			
		||||
	E(arg::R<0>, arg::P<0>)
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using L2 = F(arg::P<2>);
 | 
			
		||||
 | 
			
		||||
using L31 =	G(arg::P<0>, arg::P<2>);
 | 
			
		||||
using L32 =
 | 
			
		||||
L<Serial, arg::R<0>(arg::R<0>, arg::P<1>),
 | 
			
		||||
	H(arg::P<0>),
 | 
			
		||||
	void(arg::P<0>, arg::P<1>)
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using L33 = I(arg::R<0>);
 | 
			
		||||
 | 
			
		||||
using L3 =
 | 
			
		||||
L<Serial, arg::R<2>(arg::R<1>, arg::P<0>, arg::R<0>),
 | 
			
		||||
	L31, L32, L33
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
using L_ =
 | 
			
		||||
L<Serial, arg::R<2>(A, B, C),
 | 
			
		||||
	L1, L2, L3
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("LinksToReturnTypes") {
 | 
			
		||||
	REQUIRE(std::is_same<Pack<E>, impl::LinksToReturnTypes<L1>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<F>, impl::LinksToReturnTypes<L2>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<G>, impl::LinksToReturnTypes<L31>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<H>, impl::LinksToReturnTypes<L32>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L33>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L3>::type>{});
 | 
			
		||||
	REQUIRE(std::is_same<Pack<I>, impl::LinksToReturnTypes<L_>::type>{});
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<Pack<E, F, I>, impl::LinksToReturnTypes<L1, L2, L3>::type>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using T_ =
 | 
			
		||||
Serial<arg::R<2>(A, B, C),
 | 
			
		||||
	// 1
 | 
			
		||||
	Fun<Serial<arg::R<1>(B, C),
 | 
			
		||||
		Fun<Unary<D>, D(arg::P<1>)>,
 | 
			
		||||
		Fun<Binary<E>, E(arg::R<0>, arg::P<0>)>
 | 
			
		||||
	>, E(arg::P<1>, arg::P<2>)>,
 | 
			
		||||
	// 2
 | 
			
		||||
	Fun<Unary<F>, F(arg::P<2>)>,
 | 
			
		||||
	// 3
 | 
			
		||||
	Fun<Serial<arg::R<2>(F, A, E),
 | 
			
		||||
		Fun<Unary<G>, G(arg::P<0>, arg::P<2>)>,
 | 
			
		||||
		Fun<Serial<arg::R<0>(G, A),
 | 
			
		||||
			Fun<Unary<H>, H(arg::P<0>)>,
 | 
			
		||||
			Fun<Binary<void>, void(arg::P<0>, arg::P<1>)>
 | 
			
		||||
		>, H(arg::R<0>, arg::P<1>)>,
 | 
			
		||||
		Fun<Unary<I>, I(arg::R<0>)>
 | 
			
		||||
	>, I(arg::R<1>, arg::P<0>, arg::R<0>)>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
template<typename...>
 | 
			
		||||
using TS_ = S_;
 | 
			
		||||
 | 
			
		||||
template<typename...>
 | 
			
		||||
using TL_ = L_;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("BuildSkeleton") {
 | 
			
		||||
	using T1 = BuildSkeleton<TS_, TL_>::skeleton<Pack<>, Pack<>>;
 | 
			
		||||
	using T2 = BuildSkeletonT<S_, L_>;
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<T_, T1>{});
 | 
			
		||||
	REQUIRE(std::is_same<T_, T2>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("TreeFromSkeleton") {
 | 
			
		||||
	SECTION("simple") {
 | 
			
		||||
		struct F {};
 | 
			
		||||
 | 
			
		||||
		using Struct    = S<Serial, F>;
 | 
			
		||||
		using Links     = L<Serial, void(), void()>;
 | 
			
		||||
		using Skel      = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
		using Expected  =
 | 
			
		||||
			tmp::Tree<
 | 
			
		||||
				Branch<Serial, void ()>,
 | 
			
		||||
				tmp::Tree<Leaf<F, void ()>>
 | 
			
		||||
			>;
 | 
			
		||||
 | 
			
		||||
		using Result    = TreeFromSkeleton<Skel>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<Expected, Result>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("with links") {
 | 
			
		||||
		struct F {}; struct G {};
 | 
			
		||||
 | 
			
		||||
		using Struct    = S<Serial, S<Serial, F, G>>;
 | 
			
		||||
		using Links     = L<Serial, arg::R<0>(int&, int), L<Serial, arg::R<1>(arg::P<1>, arg::P<0>), long(arg::P<1>, arg::P<0>), int(arg::R<0>)>>;
 | 
			
		||||
		using Skel      = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
		using Expected  =
 | 
			
		||||
			tmp::Tree<
 | 
			
		||||
				Branch<Serial, arg::R<0>(int&, int)>,
 | 
			
		||||
				tmp::Tree<
 | 
			
		||||
					Branch<Serial, arg::R<1>(int, int&), int(arg::P<1>, arg::P<0>)>,
 | 
			
		||||
					tmp::Tree<Leaf<F, long(arg::P<1>, arg::P<0>)>>,
 | 
			
		||||
					tmp::Tree<Leaf<G, int(arg::R<0>)>>
 | 
			
		||||
				>
 | 
			
		||||
			>;
 | 
			
		||||
 | 
			
		||||
		using Result  = TreeFromSkeleton<Skel>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<Expected, Result>{});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("complex") {
 | 
			
		||||
		struct A0 {}; struct A1 {}; struct A2 {}; struct A3 {}; struct R {};
 | 
			
		||||
 | 
			
		||||
		using Struct    = S<Serial, A0, S<Farm, S<Serial, A1, A2>>, A0, S<Serial, A3, A3>>;
 | 
			
		||||
		using Links     = L<Serial, void(), R(), L<Farm, bool(), L<Serial, char(), short(), int()>>, R(), L<Serial, long(), float(), double()>>;
 | 
			
		||||
		using Skel      = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
		using Expected  =
 | 
			
		||||
			tmp::Tree<
 | 
			
		||||
				Branch<Serial, void()>,
 | 
			
		||||
				tmp::Tree<Leaf<A0, R()>>,
 | 
			
		||||
				tmp::Tree<
 | 
			
		||||
					Branch<Farm, bool()>,
 | 
			
		||||
					tmp::Tree<
 | 
			
		||||
						Branch<Serial, char()>,
 | 
			
		||||
						tmp::Tree<Leaf<A1, short()>>,
 | 
			
		||||
						tmp::Tree<Leaf<A2, int()>>
 | 
			
		||||
					>
 | 
			
		||||
				>,
 | 
			
		||||
				tmp::Tree<Leaf<A0, R()>>,
 | 
			
		||||
				tmp::Tree<
 | 
			
		||||
					Branch<Serial, long()>,
 | 
			
		||||
					tmp::Tree<Leaf<A3, float()>>,
 | 
			
		||||
					tmp::Tree<Leaf<A3, double()>>
 | 
			
		||||
				>
 | 
			
		||||
			>;
 | 
			
		||||
 | 
			
		||||
		using Result    = TreeFromSkeleton<Skel>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(std::is_same<Expected, Result>{});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("ToSkeleton") {
 | 
			
		||||
	struct A0 {}; struct A1 {}; struct A2 {}; struct A3 {}; struct R {};
 | 
			
		||||
	using Struct    = S<Serial, A0, S<Farm, S<Serial, A1, A2>>, A0, S<Serial, A3, A3>>;
 | 
			
		||||
	using Links     = L<Serial, void(), R(), L<Farm, bool(), L<Serial, char(), short(), int()>>, R(), L<Serial, long(), float(), double()>>;
 | 
			
		||||
	using Expected  = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
	using Input     =
 | 
			
		||||
		tmp::Tree<
 | 
			
		||||
			Branch<Serial, void()>,
 | 
			
		||||
			tmp::Tree<Leaf<A0, R()>>,
 | 
			
		||||
			tmp::Tree<
 | 
			
		||||
				Branch<Farm, bool()>,
 | 
			
		||||
				tmp::Tree<
 | 
			
		||||
					Branch<Serial, char()>,
 | 
			
		||||
					tmp::Tree<Leaf<A1, short()>>,
 | 
			
		||||
					tmp::Tree<Leaf<A2, int()>>
 | 
			
		||||
				>
 | 
			
		||||
			>,
 | 
			
		||||
			tmp::Tree<Leaf<A0, R()>>,
 | 
			
		||||
			tmp::Tree<
 | 
			
		||||
				Branch<Serial, long()>,
 | 
			
		||||
				tmp::Tree<Leaf<A3, float()>>,
 | 
			
		||||
				tmp::Tree<Leaf<A3, double()>>
 | 
			
		||||
			>
 | 
			
		||||
		>;
 | 
			
		||||
 | 
			
		||||
	using Result = SkeletonFromTree<Input>;
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<Expected, Result>{});
 | 
			
		||||
	REQUIRE(std::is_same<Expected, SkeletonFromTree<TreeFromSkeleton<Expected>>>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("SkeletonParallelHeight") {
 | 
			
		||||
	SECTION("serial") {
 | 
			
		||||
		struct F {}; struct G {};
 | 
			
		||||
		using Struct  = S<Serial, S<Serial, F, G>>;
 | 
			
		||||
		using Links   = L<Serial, arg::R<0>(int&, int), L<Serial, arg::R<1>(arg::P<1>, arg::P<0>), long(arg::P<1>, arg::P<0>), int(arg::R<0>)>>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(skeletonParallelHeight<Skel> == 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("par2") {
 | 
			
		||||
		struct A0 {}; struct A1 {}; struct A2 {};
 | 
			
		||||
		using Struct  = S<Serial, A0, S<Farm, S<Farm, A1>>, S<Farm, A2>>;
 | 
			
		||||
		using Links   = L<Serial, int(), int(), L<Farm, int(), L<Farm, int(), int()>>, L<Farm, int(), int()>>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(skeletonParallelHeight<Skel> == 2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("par4") {
 | 
			
		||||
		struct A0 {};
 | 
			
		||||
		using Struct  = S<Farm, S<Farm, S<Farm, S<Farm, A0>>>>;
 | 
			
		||||
		using Links   = L<Farm, int(), L<Farm, int(), L<Farm, int(), L<Farm, int(), int()>>>>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(skeletonParallelHeight<Skel> == 4);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SECTION("complex") {
 | 
			
		||||
		struct A0 {};
 | 
			
		||||
		using Struct  = S<Farm, S<Serial, S<Farm, S<Farm, A0>>, S<Farm, S<Serial, S<Farm, A0>>>>>;
 | 
			
		||||
		using Links   = L<Farm, int(), L<Serial, int(), L<Farm, int(), L<Farm, int(), int()>>, L<Farm, int(), L<Serial, int(), L<Farm, int(), int()>>>>>;
 | 
			
		||||
		using Skel    = BuildSkeletonT<Struct, Links>;
 | 
			
		||||
 | 
			
		||||
		REQUIRE(skeletonParallelHeight<Skel> == 3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								tests/skeleton/link/args.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								tests/skeleton/link/args.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
#include <catch.hpp>
 | 
			
		||||
#include <alsk/skeleton/link/args.h>
 | 
			
		||||
#include <alsk/context/context.h>
 | 
			
		||||
 | 
			
		||||
using namespace alsk;
 | 
			
		||||
using tmp::Pack;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("ArgType") {
 | 
			
		||||
	using P = Pack<struct A, struct B, struct C>;
 | 
			
		||||
	using R = Pack<struct D, struct E, struct F>;
 | 
			
		||||
	using X = Pack<struct G, struct H>;
 | 
			
		||||
 | 
			
		||||
	using Placeholders = arg::Placeholders<P, R, X>;
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<struct A, ArgType<arg::P<0>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct B, ArgType<arg::P<1>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct C, ArgType<arg::P<2>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct D, ArgType<arg::R<0>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct E, ArgType<arg::R<1>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct F, ArgType<arg::R<2>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct H, ArgType<arg::RNG, Placeholders>>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("ArgGet") {
 | 
			
		||||
	std::tuple<int, int, int> p{0, 1, 2};
 | 
			
		||||
	std::tuple<int, int, int> r{3, 4, 5};
 | 
			
		||||
	std::tuple<int, int> x{6, 7};
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::get<0>(p) == ArgGet<arg::P<0>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<1>(p) == ArgGet<arg::P<1>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<2>(p) == ArgGet<arg::P<2>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<0>(r) == ArgGet<arg::R<0>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<1>(r) == ArgGet<arg::R<1>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<2>(r) == ArgGet<arg::R<2>>::get(p, r, x));
 | 
			
		||||
	REQUIRE(std::get<1>(x) == ArgGet<arg::RNG>::get(p, r, x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("PRFilter") {}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("RealType") {
 | 
			
		||||
	using P = Pack<struct A, struct B, struct C>;
 | 
			
		||||
	using R = Pack<struct D, struct E, struct F>;
 | 
			
		||||
	using X = Pack<struct G, struct H>;
 | 
			
		||||
 | 
			
		||||
	using Placeholders = arg::Placeholders<P, R, X>;
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<struct A, RealType<arg::P<0>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct B, RealType<arg::P<1>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct C, RealType<arg::P<2>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct D, RealType<arg::R<0>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct E, RealType<arg::R<1>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct F, RealType<arg::R<2>, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct H, RealType<arg::RNG, Placeholders>>{});
 | 
			
		||||
	REQUIRE(std::is_same<struct _, RealType<struct _, Placeholders>>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("RealSignature") {
 | 
			
		||||
	using P = Pack<struct A, struct B, struct C>;
 | 
			
		||||
	using R = Pack<struct D, struct E, struct F>;
 | 
			
		||||
	using X = Pack<struct G, struct H>;
 | 
			
		||||
 | 
			
		||||
	using Placeholders = arg::Placeholders<P, R, X>;
 | 
			
		||||
 | 
			
		||||
	using S = int&(arg::P<0>, arg::R<1>, arg::P<2>, arg::RNG, struct _);
 | 
			
		||||
	using Q = std::function<int&(struct A, struct E, struct C, struct H, struct _)>;
 | 
			
		||||
 | 
			
		||||
	REQUIRE(std::is_same<Q, RealSignature<S, Placeholders>>{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Returns") {}
 | 
			
		||||
TEST_CASE("Execute") {}
 | 
			
		||||
		Reference in New Issue
	
	Block a user