Skip to content

Commit

Permalink
Improve documentation on how to work with containers
Browse files Browse the repository at this point in the history
* document simd_for_each
* document simdize<Iterator>
* move makeContainer documentation into Containers group
* extend simdize test to cover what's documented

Signed-off-by: Matthias Kretz <kretz@kde.org>
  • Loading branch information
mattkretz committed Aug 31, 2018
1 parent fa9cf78 commit 246ca17
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 13 deletions.
45 changes: 38 additions & 7 deletions common/algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,47 @@ template<typename Mask> constexpr bool some_of(const Mask &m) { return m.isMix()
constexpr bool some_of(bool) { return false; }
//@}

template <typename InputIt, typename UnaryFunction>
#ifdef DOXYGEN
/**
* \ingroup Utilities
* \headerfile algorithms.h <Vc/Vc>
*
* Vc variant of the `std::for_each` algorithm.
*
* This algorithm calls \p f with one argument of type
* `Vc::Vector<` *iterator value type* `, ` *unspecified* `>` as often as is needed to
* iterate over the complete range from \p first to \p last.
* It will try to use the best vector size (VectorAbi) to work on the largest chunks
* possible.
* To support aligned loads (and stores) and to support arbitrary range distances, the
* algorithm may require the use of `Vc::VectorAbi` types that work on fewer elements in
* parallel.
*
* The following example requires C++14 for generic lambdas. If you don't have generic
* lambdas available you can use a "classic" functor type with a templated call operator
* instead.
*
* \code
* void scale(std::vector<double> &data, double factor) {
* Vc::simd_for_each(data.begin(), data.end(), [&](auto v) {
* v *= factor;
* });
* }
* \endcode
*/
template <class InputIt, class UnaryFunction>
UnaryFunction simd_for_each(InputIt first, InputIt last, UnaryFunction f);
#else
template <class InputIt, class UnaryFunction,
class ValueType = typename std::iterator_traits<InputIt>::value_type>
inline enable_if<
std::is_arithmetic<typename std::iterator_traits<InputIt>::value_type>::value &&
Traits::is_functor_argument_immutable<
UnaryFunction,
Vector<typename std::iterator_traits<InputIt>::value_type>>::value,
std::is_arithmetic<ValueType>::value &&
Traits::is_functor_argument_immutable<UnaryFunction, Vector<ValueType>>::value,
UnaryFunction>
simd_for_each(InputIt first, InputIt last, UnaryFunction f)
{
typedef Vector<typename std::iterator_traits<InputIt>::value_type> V;
typedef Scalar::Vector<typename std::iterator_traits<InputIt>::value_type> V1;
typedef Vector<ValueType> V;
typedef Scalar::Vector<ValueType> V1;
for (; reinterpret_cast<std::uintptr_t>(std::addressof(*first)) &
(V::MemoryAlignment - 1) &&
first != last;
Expand Down Expand Up @@ -135,6 +165,7 @@ simd_for_each(InputIt first, InputIt last, UnaryFunction f)
}
return std::move(f);
}
#endif

template <typename InputIt, typename UnaryFunction>
inline enable_if<
Expand Down
4 changes: 2 additions & 2 deletions common/makeContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ namespace Vc_VERSIONED_NAMESPACE
} // anonymous namespace

/**
* \ingroup Utilities
* \headerfile Utils
* \ingroup Containers
* \headerfile makeContainer.h <Vc/Utils>
*
* Construct a container of Vc vectors from a std::initializer_list of scalar entries.
*
Expand Down
38 changes: 35 additions & 3 deletions common/simdize.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Automatic type vectorization.
The simdize<T> expression transforms the type \c T to a vectorized variant. This requires the type
\c T to be a class template instance.
Struct Vectorization
======================
The `Vc::simdize<T>` expression transforms the type \c T to a vectorized type. This requires the type
\c T to be a class template instance or an arithmetic type.
Example:
First, we declare a class template for a three-dimensional point. The template parameter \c T
Expand All @@ -56,7 +59,10 @@ template <typename T> struct PointTemplate
PointTemplate(T xx, T yy, T zz) : x{xx}, y{yy}, z{zz} {};
// The following function will automatically be vectorized in the PointV type.
T distance_to_origin() const { return std::sqrt(x * x + y * y + z * z); }
T distance_to_origin() const {
using std::sqrt;
return sqrt(x * x + y * y + z * z);
}
};
\endcode
Expand Down Expand Up @@ -85,6 +91,32 @@ const Point most_distant = extract(pv, (l.max() == l).firstOne());
std::cout << '(' << most_distant.x << ", " << most_distant.y << ", " << most_distant.z << ")\n";
// prints (7, 8, 9) with float_v::size() == 8
\endcode
Iterator Vectorization
======================
`Vc::simdize<Iterator>` can also be used to turn an iterator type into a new iterator type with `Vc::simdize<Iterator::value_type>` as its `value_type`.
Note that `Vc::simdize<double>` turns into `Vc::Vector<double>`, which makes it easy to iterate over a given container of builtin arithmetics using `Vc::Vector`.
\code
void classic(const std::vector<Point> &data) {
using It = std::vector<Point>::const_iterator;
const It end = data.end();
for (It it = data.begin(); it != end; ++it) {
Point x = *it;
do_something(x);
}
}
void vectorized(const std::vector<float> &data) {
using It = Vc::simdize<std::vector<Point>::const_iterator>;
const It end = data.end();
for (It it = data.begin(); it != end; ++it) {
Vc::simdize<Point> x = *it; // i.e. PointV
do_something(x);
}
}
\endcode
*/
namespace Vc_VERSIONED_NAMESPACE
{
Expand Down
26 changes: 25 additions & 1 deletion tests/simdize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,6 @@ TEST(vector_iterator_vectorization)
COMPARE(next, b);
COMPARE(*next, *b);


float_v reference = list.size() - float_v::IndexesFromZero();
for (; b != e; ++b, reference -= float_v::size()) {
float_v x = *b;
Expand All @@ -494,6 +493,31 @@ TEST(vector_iterator_vectorization)
COMPARE(x, reference);
COMPARE(*b, reference);
}

// also test const_iterator
reference = list.size() - float_v::IndexesFromZero() + 1;
using LCIV = simdize<L::const_iterator>;
LCIV it = list.cbegin();
const LCIV ce = list.cend();
for (; it != ce; ++it, reference -= float_v::size()) {
float_v x = *it;
COMPARE(x, reference);
COMPARE(*it, reference);
}
}
{
using L = std::vector<std::tuple<short, float>>;
using LIV = simdize<L::iterator>;
L list;
for (auto i = 1024; i; --i) {
list.emplace_back(i, i);
}
const LIV end_it = list.end();
for (LIV it = list.begin(); it != end_it; ++it) {
simdize<std::tuple<short, float>> x = *it;
COMPARE(std::get<0>(x), std::get<0>(*it));
COMPARE(std::get<1>(x), std::get<1>(*it));
}
}
}

Expand Down

0 comments on commit 246ca17

Please sign in to comment.