Skip to content

Commit

Permalink
Add explicit deduction guides for blocked_nd_range (#1525)
Browse files Browse the repository at this point in the history
* Enable CTAD for blocked_rangeNd since C++17

* Fix constraits test failure

* Extend implementation with tests and explicit deduction guide

* Remove unnecessary helper function

* Simplify the deduction guide

* Add deduction guide for blocked_range type

* Enable CTAD for blocked_rangeNd since C++17

* Fix constraits test failure

* Fix merging issue

* Add new deduction guides and test

* Update copyright years

* Update copyright years

* Save progress

* Apply review comments + introduce preview macros

* Fix fancy value

* Add single C array support

---------

Co-authored-by: Ruslan Arutyunyan <[email protected]>
  • Loading branch information
kboyarinov and rarutyun authored Jan 24, 2025
1 parent d4b5ee5 commit 9d45787
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 1 deletion.
37 changes: 37 additions & 0 deletions include/oneapi/tbb/blocked_nd_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,43 @@ class blocked_nd_range : public blocked_nd_range_impl<Value, N> {
using base::base;
};

#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT && __TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES
// blocked_nd_range(const dim_range_type& dim0, const dim_range_type& dim1, ...)
// while the arguments are passed as braced-init-lists
// Works only for 2 and more arguments since the deduction from
// single braced-init-list or single C-array argument prefers the multi-dimensional range
// Only braced-init-lists of size 2 and 3 are allowed since dim_range_type may only
// be constructed from 2 or 3 arguments
template <typename Value, unsigned int... Ns,
typename = std::enable_if_t<sizeof...(Ns) >= 2>,
typename = std::enable_if_t<(... && (Ns == 2 || Ns == 3))>>
blocked_nd_range(const Value (&... dim)[Ns])
-> blocked_nd_range<Value, sizeof...(Ns)>;

// blocked_nd_range(const dim_range_type& dim0, const dim_range_type& dim1, ...)
// while the arguments are passed as blocked_range objects of the same type
template <typename Value, typename... Values,
typename = std::enable_if_t<(... && std::is_same_v<Value, Values>)>>
blocked_nd_range(blocked_range<Value>, blocked_range<Values>...)
-> blocked_nd_range<Value, 1 + sizeof...(Values)>;

// blocked_nd_range(const value_type (&size)[N], size_type grainsize = 1)
template <typename Value, unsigned int N>
blocked_nd_range(const Value (&)[N], typename blocked_nd_range<Value, N>::size_type = 1)
-> blocked_nd_range<Value, N>;

// blocked_nd_range(blocked_nd_range<Value, N>&, oneapi::tbb::split)
template <typename Value, unsigned int N>
blocked_nd_range(blocked_nd_range<Value, N>, oneapi::tbb::split)
-> blocked_nd_range<Value, N>;

// blocked_nd_range(blocked_nd_range<Value, N>&, oneapi::tbb::proportional_split)
template <typename Value, unsigned int N>
blocked_nd_range(blocked_nd_range<Value, N>, oneapi::tbb::proportional_split)
-> blocked_nd_range<Value, N>;

#endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT && __TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES

} // namespace d1
} // namespace detail

Expand Down
4 changes: 4 additions & 0 deletions include/oneapi/tbb/detail/_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,8 @@
#define __TBB_PREVIEW_PARALLEL_PHASE 1
#endif

#if TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES
#define __TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES 1
#endif

#endif // __TBB_detail__config_H
3 changes: 3 additions & 0 deletions test/common/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
#ifndef TBB_PREVIEW_PARALLEL_PHASE
#define TBB_PREVIEW_PARALLEL_PHASE 1
#endif
#ifndef TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES
#define TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES 1
#endif
#endif

#include "oneapi/tbb/detail/_config.h"
Expand Down
147 changes: 146 additions & 1 deletion test/tbb/test_blocked_range.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2005-2024 Intel Corporation
Copyright (c) 2005-2025 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -192,3 +192,148 @@ TEST_CASE("constraints for blocked_nd_range value") {
}

#endif // __TBB_CPP20_CONCEPTS_PRESENT

#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT && __TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES
template <typename T>
void test_deduction_guides() {
using oneapi::tbb::blocked_nd_range;
static_assert(std::is_constructible<T, int>::value, "Incorrect test setup");
// T as a grainsize in braced-init-list constructions should be used since only
// the same type is allowed by the braced-init-list
static_assert(std::is_convertible<T, typename blocked_nd_range<T, 1>::size_type>::value,
"Incorrect test setup");

std::vector<T> v;
using iterator = typename decltype(v)::iterator;

oneapi::tbb::blocked_range<T> dim_range(0, 100);

blocked_nd_range<T, 2> source_range(dim_range, dim_range);

{
blocked_nd_range range(dim_range, dim_range, dim_range);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 3>>);
}
{
blocked_nd_range range({v.begin(), v.end()}, {v.begin(), v.end()});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<iterator, 2>>);
}
{
blocked_nd_range range({T{0}, T{100}}, {T{0}, T{100}, T{5}}, {T{0}, T{100}}, {T{0}, T{100}, T{5}});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 4>>);
}
{
blocked_nd_range range({T{100}});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 1>>);
}
{
T array[1] = {100};
blocked_nd_range range(array);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 1>>);
}
{
blocked_nd_range range({T{100}}, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 1>>);
}
{
T array[1] = {100};
blocked_nd_range range(array, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 1>>);
}
{
blocked_nd_range range({T{100}, T{200}}, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 2>>);
}
{
blocked_nd_range range({T{100}, T{200}});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 2>>);
}
{
T array[2] = {100, 200};
blocked_nd_range range(array, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 2>>);
}
{
blocked_nd_range range({T{100}, T{200}, T{300}}, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 3>>);
}
{
blocked_nd_range range({T{100}, T{200}, T{300}});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 3>>);
}
{
T array[3] = {100, 200, 300};
blocked_nd_range range(array, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 3>>);
}
{
blocked_nd_range range({T{100}, T{200}, T{300}, T{400}});
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 4>>);
}
{
T array[4] = {100, 200, 300, 400};
blocked_nd_range range(array);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 4>>);

}
{
blocked_nd_range range({T{100}, T{200}, T{300}, T{400}}, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 4>>);
}
{
T array[4] = {100, 200, 300, 400};
blocked_nd_range range(array, 5);
static_assert(std::is_same_v<decltype(range), blocked_nd_range<T, 4>>);
}
{
blocked_nd_range range(source_range, oneapi::tbb::split{});
static_assert(std::is_same_v<decltype(range), decltype(source_range)>);
}
{
blocked_nd_range range(source_range, oneapi::tbb::proportional_split{1, 3});
static_assert(std::is_same_v<decltype(range), decltype(source_range)>);
}
{
blocked_nd_range range(source_range);
static_assert(std::is_same_v<decltype(range), decltype(source_range)>);
}
{
blocked_nd_range range(std::move(source_range));
static_assert(std::is_same_v<decltype(range), decltype(source_range)>);
}
}

class fancy_value {
public:
fancy_value(std::size_t real_value) : my_real_value(real_value) {}
fancy_value(const fancy_value&) = default;
~fancy_value() = default;
fancy_value& operator=(const fancy_value&) = default;

friend bool operator<(const fancy_value& lhs, const fancy_value& rhs) {
return lhs.my_real_value < rhs.my_real_value;
}
friend std::size_t operator-(const fancy_value& lhs, const fancy_value& rhs) {
return lhs.my_real_value - rhs.my_real_value;
}
friend std::size_t operator-(const fancy_value& lhs, std::size_t offset) {
return lhs.my_real_value - offset;
}
friend fancy_value operator+(const fancy_value& lhs, std::size_t offset) {
return fancy_value(lhs.my_real_value + offset);
}

operator std::size_t() const {
return my_real_value;
}
private:
std::size_t my_real_value;
};

//! Testing blocked_nd_range deduction guides
//! \brief \ref interface \ref requirement
TEST_CASE("blocked_nd_range deduction guides") {
test_deduction_guides<int>();
test_deduction_guides<fancy_value>();
}
#endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT && __TBB_PREVIEW_BLOCKED_ND_RANGE_DEDUCTION_GUIDES

0 comments on commit 9d45787

Please sign in to comment.