Skip to content

Instantly share code, notes, and snippets.

@BillyONeal
Created October 19, 2018 23:23
Show Gist options
  • Save BillyONeal/087e421bc03deecaaade8b991e4ed0be to your computer and use it in GitHub Desktop.
Save BillyONeal/087e421bc03deecaaade8b991e4ed0be to your computer and use it in GitHub Desktop.
Parallel Type Requirements Test Cases
struct inputType {
inputType() = delete;
/* implicit */ inputType(int) {} // so that the test can make an array
inputType(const inputType&) = delete;
inputType& operator=(const inputType&) = delete;
};
struct bopResult {
bopResult() = delete;
/* implicit */ bopResult(int) {}
bopResult(const bopResult&) = delete;
bopResult& operator=(const bopResult&) = delete;
};
struct intermediateType {
intermediateType() = delete;
explicit intermediateType(int) {} // so that the test can make one of these
explicit intermediateType(inputType&) {} // Intermediate tmp(*first)
explicit intermediateType(bopResult&&) {} // Intermediate tmp(binary_op((one of tmp, move(tmp), *first), *first))
intermediateType(const intermediateType&) = delete;
intermediateType(intermediateType&&) = default; // tmp = move(tmp)
intermediateType& operator=(const intermediateType&) = delete;
intermediateType& operator=(intermediateType&&) = default; // for the exclusive versions only
// tmp = binary_op((one of tmp, move(tmp), *first), *first)
intermediateType& operator=(bopResult&&) { return *this; }
};
struct outputType {
outputType() = delete;
/* implicit */ outputType(int) {} // so that the test can make an array
outputType(const outputType&) = delete;
outputType& operator=(const outputType&) = delete;
outputType& operator=(outputType&&) = delete;
// in the first pass
outputType& operator=(intermediateType&) { return *this; }
outputType& operator=(intermediateType&&) { return *this; }
// in the second pass
outputType& operator=(bopResult&&) { return *this; }
};
struct typesBop {
// tmp = binary_op( (one of tmp, move(tmp), *first), *first)
bopResult operator()(intermediateType&, inputType&) { return 0; }
bopResult operator()(intermediateType&&, inputType&) { return 0; }
bopResult operator()(inputType&, inputType&) { return 0; }
// tmp = binary_op( (one of tmp, move(tmp)), (one of tmp, move(tmp)) )
bopResult operator()(intermediateType& , intermediateType& ) { return 0; }
bopResult operator()(intermediateType& , intermediateType&&) { return 0; }
bopResult operator()(intermediateType&&, intermediateType& ) { return 0; }
bopResult operator()(intermediateType&&, intermediateType&&) { return 0; }
// *result = binary_op(tmp, move(*result))
bopResult operator()(intermediateType&, outputType&&) { return 0; }
};
void test_case_exclusive_scan_init_writes_intermediate_type() {
inputType input[2]{0, 0};
outputType output[2]{0, 0};
exclusive_scan(begin(input), end(input), output, intermediateType{0}, typesBop{});
exclusive_scan(par, begin(input), end(input), output, intermediateType{0}, typesBop{});
}
struct inputType {
inputType() = delete;
/* implicit */ inputType(int) {} // so that the test can make an array
inputType(const inputType&) = delete;
inputType& operator=(const inputType&) = delete;
};
struct bopResult {
bopResult() = delete;
/* implicit */ bopResult(int) {}
bopResult(const bopResult&) = delete;
bopResult& operator=(const bopResult&) = delete;
};
struct intermediateType {
intermediateType() = delete;
explicit intermediateType(int) {} // so that the test can make one of these
explicit intermediateType(inputType&) {} // Intermediate tmp(*first)
explicit intermediateType(bopResult&&) {} // Intermediate tmp(binary_op((one of tmp, move(tmp), *first), *first))
intermediateType(const intermediateType&) = delete;
intermediateType(intermediateType&&) = default; // tmp = move(tmp)
intermediateType& operator=(const intermediateType&) = delete;
intermediateType& operator=(intermediateType&&) = delete;
// tmp = binary_op((one of tmp, move(tmp), *first), *first)
intermediateType& operator=(bopResult&&) { return *this; }
};
struct outputType {
outputType() = delete;
/* implicit */ outputType(int) {} // so that the test can make an array
outputType(const outputType&) = delete;
outputType& operator=(const outputType&) = delete;
outputType& operator=(outputType&&) = delete;
// in the first pass
outputType& operator=(intermediateType&) { return *this; }
outputType& operator=(intermediateType&&) { return *this; }
// in the second pass
outputType& operator=(bopResult&&) { return *this; }
};
struct typesBop {
// tmp = binary_op( (one of tmp, move(tmp), *first), *first)
bopResult operator()(intermediateType&, inputType&) { return 0; }
bopResult operator()(intermediateType&&, inputType&) { return 0; }
bopResult operator()(inputType&, inputType&) { return 0; }
// tmp = binary_op( (one of tmp, move(tmp)), (one of tmp, move(tmp)) )
bopResult operator()(intermediateType& , intermediateType& ) { return 0; }
bopResult operator()(intermediateType& , intermediateType&&) { return 0; }
bopResult operator()(intermediateType&&, intermediateType& ) { return 0; }
bopResult operator()(intermediateType&&, intermediateType&&) { return 0; }
// *result = binary_op(tmp, move(*result))
bopResult operator()(intermediateType&, outputType&&) { return 0; }
};
void test_case_inclusive_scan_init_writes_intermediate_type() {
inputType input[2]{0, 0};
outputType output[2]{0, 0};
inclusive_scan(begin(input), end(input), output, typesBop{}, intermediateType{0});
inclusive_scan(par, begin(input), end(input), output, typesBop{}, intermediateType{0});
}
vector<unique_ptr<vector<unsigned int>>> get_move_only_test_data(const size_t testSize) {
vector<unique_ptr<vector<unsigned int>>> testData;
testData.reserve(testSize);
for (size_t idx = 0; idx < testSize; ++idx) {
testData.emplace_back(make_unique<vector<unsigned int>>(1, static_cast<unsigned int>(idx)));
}
return testData;
}
template<class ExPo>
void test_case_move_only(ExPo&& exec, const size_t testSize) {
// one could argue that this mutates the input which is presently disallowed by the parallel
// algorithms, but the standard is unclear here and if this isn't allowed, the standard
// is bad and should feel bad
auto testData = get_move_only_test_data(testSize);
unique_ptr<vector<unsigned int>> result = reduce(forward<ExPo>(exec),
make_move_iterator(testData.begin()), make_move_iterator(testData.end()),
make_unique<vector<unsigned int>>(),
[](unique_ptr<vector<unsigned int>> lhs, unique_ptr<vector<unsigned int>> rhs) {
lhs->insert(lhs->end(), rhs->begin(), rhs->end());
return lhs;
});
sort(result->begin(), result->end());
for (size_t idx = 0; idx < testSize; ++idx) {
verify((*result)[idx] == idx);
}
}
struct inputType {
inputType() = delete;
/* implicit */ inputType(int) {} // so that the test can make an array
inputType(const inputType&) = delete;
inputType& operator=(const inputType&) = delete;
};
struct transformedType {
transformedType() = delete;
/* implicit */ transformedType(int) {}
transformedType(const transformedType&) = delete;
transformedType& operator=(const transformedType&) = delete;
};
struct bopResult {
bopResult() = delete;
/* implicit */ bopResult(int) {}
bopResult(const bopResult&) = delete;
bopResult& operator=(const bopResult&) = delete;
};
struct intermediateType {
intermediateType() = delete;
explicit intermediateType(int) {} // so that the test can make one of these
explicit intermediateType(transformedType&&) {} // Intermediate tmp(unary_op(*first))
// Intermediate tmp(binary_op((one of tmp, move(tmp), unary_op(*first)), unary_op(*first)))
explicit intermediateType(bopResult&&) {}
intermediateType(const intermediateType&) = delete;
intermediateType(intermediateType&&) = default; // tmp = move(tmp)
intermediateType& operator=(const intermediateType&) = delete;
intermediateType& operator=(intermediateType&&) = default;
// tmp = binary_op((one of tmp, move(tmp), *first), *first)
intermediateType& operator=(bopResult&&) { return *this; }
};
struct outputType {
outputType() = delete;
/* implicit */ outputType(int) {} // so that the test can make an array
outputType(const outputType&) = delete;
outputType& operator=(const outputType&) = delete;
outputType& operator=(outputType&&) = delete;
// in the first pass
outputType& operator=(intermediateType&) { return *this; }
outputType& operator=(intermediateType&&) { return *this; }
// in the second pass
outputType& operator=(bopResult&&) { return *this; }
};
struct transformUop {
transformedType operator()(inputType&) { return 0; };
};
struct typesBop {
// tmp = binary_op( (one of tmp, move(tmp), unary_op(*first)), unary_op(*first))
bopResult operator()(intermediateType&, transformedType&&) { return 0; }
bopResult operator()(intermediateType&&, transformedType&&) { return 0; }
bopResult operator()(transformedType&&, transformedType&&) { return 0; }
// tmp = binary_op( (one of tmp, move(tmp)), (one of tmp, move(tmp)) )
bopResult operator()(intermediateType& , intermediateType& ) { return 0; }
bopResult operator()(intermediateType& , intermediateType&&) { return 0; }
bopResult operator()(intermediateType&&, intermediateType& ) { return 0; }
bopResult operator()(intermediateType&&, intermediateType&&) { return 0; }
// *result = binary_op(tmp, move(*result))
bopResult operator()(intermediateType&, outputType&&) { return 0; }
};
void test_case_transform_exclusive_scan_init_writes_intermediate_type() {
inputType input[2]{0, 0};
outputType output[2]{0, 0};
transform_exclusive_scan(begin(input), end(input), output, intermediateType{0}, typesBop{}, transformUop{});
transform_exclusive_scan(par, begin(input), end(input), output, intermediateType{0}, typesBop{}, transformUop{});
}
struct inputType {
inputType() = delete;
/* implicit */ inputType(int) {} // so that the test can make an array
inputType(const inputType&) = delete;
inputType& operator=(const inputType&) = delete;
};
struct transformedType {
transformedType() = delete;
/* implicit */ transformedType(int) {}
transformedType(const transformedType&) = delete;
transformedType& operator=(const transformedType&) = delete;
};
struct bopResult {
bopResult() = delete;
/* implicit */ bopResult(int) {}
bopResult(const bopResult&) = delete;
bopResult& operator=(const bopResult&) = delete;
};
struct intermediateType {
intermediateType() = delete;
explicit intermediateType(int) {} // so that the test can make one of these
explicit intermediateType(transformedType&&) {} // Intermediate tmp(unary_op(*first))
// Intermediate tmp(binary_op((one of tmp, move(tmp), unary_op(*first)), unary_op(*first)))
explicit intermediateType(bopResult&&) {}
intermediateType(const intermediateType&) = delete;
intermediateType(intermediateType&&) = default; // tmp = move(tmp)
intermediateType& operator=(const intermediateType&) = delete;
intermediateType& operator=(intermediateType&&) = delete;
// tmp = binary_op((one of tmp, move(tmp), *first), *first)
intermediateType& operator=(bopResult&&) { return *this; }
};
struct outputType {
outputType() = delete;
/* implicit */ outputType(int) {} // so that the test can make an array
outputType(const outputType&) = delete;
outputType& operator=(const outputType&) = delete;
outputType& operator=(outputType&&) = delete;
// in the first pass
outputType& operator=(intermediateType&) { return *this; }
outputType& operator=(intermediateType&&) { return *this; }
// in the second pass
outputType& operator=(bopResult&&) { return *this; }
};
struct transformUop {
transformedType operator()(inputType&) { return 0; };
};
struct typesBop {
// tmp = binary_op( (one of tmp, move(tmp), unary_op(*first)), unary_op(*first))
bopResult operator()(intermediateType&, transformedType&&) { return 0; }
bopResult operator()(intermediateType&&, transformedType&&) { return 0; }
bopResult operator()(transformedType&&, transformedType&&) { return 0; }
// tmp = binary_op( (one of tmp, move(tmp)), (one of tmp, move(tmp)) )
bopResult operator()(intermediateType& , intermediateType& ) { return 0; }
bopResult operator()(intermediateType& , intermediateType&&) { return 0; }
bopResult operator()(intermediateType&&, intermediateType& ) { return 0; }
bopResult operator()(intermediateType&&, intermediateType&&) { return 0; }
// *result = binary_op(tmp, move(*result))
bopResult operator()(intermediateType&, outputType&&) { return 0; }
};
void test_case_transform_inclusive_scan_init_writes_intermediate_type() {
inputType input[2]{0, 0};
outputType output[2]{0, 0};
transform_inclusive_scan(begin(input), end(input), output, typesBop{}, transformUop{}, intermediateType{0});
transform_inclusive_scan(par, begin(input), end(input), output, typesBop{}, transformUop{}, intermediateType{0});
}
vector<unique_ptr<vector<unsigned int>>> get_move_only_test_data(const size_t testSize) {
vector<unique_ptr<vector<unsigned int>>> testData;
testData.reserve(testSize);
for (size_t idx = 0; idx < testSize; ++idx) {
testData.emplace_back(make_unique<vector<unsigned int>>(1, static_cast<unsigned int>(idx)));
}
return testData;
}
// one could argue that the move-only examples mutate the input which is presently disallowed by the
// parallel algorithms, but the standard is unclear here and if this isn't allowed, the standard
// is bad and should feel bad
template<class ExPo>
void test_case_move_only_binary(ExPo&& exec, const size_t testSize) {
auto testData1 = get_move_only_test_data(testSize);
auto testData2 = get_move_only_test_data(testSize);
unique_ptr<vector<unsigned int>> result = transform_reduce(forward<ExPo>(exec),
make_move_iterator(testData1.begin()), make_move_iterator(testData1.end()),
make_move_iterator(testData2.begin()),
make_unique<vector<unsigned int>>(),
[](unique_ptr<vector<unsigned int>> lhs, unique_ptr<vector<unsigned int>> rhs) {
lhs->insert(lhs->end(), rhs->begin(), rhs->end());
return lhs;
},
[](unique_ptr<vector<unsigned int>> lhs, unique_ptr<vector<unsigned int>> rhs) {
verify(lhs->size() == 1); // should only be called directly on the input sequence
verify(rhs->size() == 1);
unsigned int lhsInt = (*lhs)[0];
unsigned int rhsInt = (*rhs)[0];
verify(lhsInt == rhsInt);
(*lhs)[0] = lhsInt * rhsInt;
return lhs;
});
sort(result->begin(), result->end());
for (size_t idx = 0; idx < testSize; ++idx) {
verify((*result)[idx] == idx * idx);
}
}
template<class ExPo>
void test_case_move_only(ExPo&& exec, const size_t testSize) {
auto testData = get_move_only_test_data(testSize);
unique_ptr<vector<unsigned int>> result = transform_reduce(forward<ExPo>(exec),
make_move_iterator(testData.begin()), make_move_iterator(testData.end()),
make_unique<vector<unsigned int>>(),
[](unique_ptr<vector<unsigned int>> lhs, unique_ptr<vector<unsigned int>> rhs) {
lhs->insert(lhs->end(), rhs->begin(), rhs->end());
return lhs;
},
[](unique_ptr<vector<unsigned int>> target) {
verify(target->size() == 1); // should only be called directly on the input sequence
target->back() *= 10;
return target;
});
sort(result->begin(), result->end());
for (size_t idx = 0; idx < testSize; ++idx) {
verify((*result)[idx] == idx * 10);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment