Skip to content

Commit 85efe71

Browse files
committed
Implementation of arange algorithm
1 parent 9ce8aee commit 85efe71

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/***************************************************************************
2+
* Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3+
* Martin Renou *
4+
* Copyright (c) QuantStack *
5+
* Copyright (c) Serge Guelton *
6+
* *
7+
* Distributed under the terms of the BSD 3-Clause License. *
8+
* *
9+
* The full license is in the file LICENSE, distributed with this software. *
10+
****************************************************************************/
11+
12+
#ifndef XSIMD_ALGORITHMS_ARANGE_HPP
13+
#define XSIMD_ALGORITHMS_ARANGE_HPP
14+
15+
#include "xsimd/xsimd.hpp"
16+
17+
#include <iterator>
18+
19+
namespace xsimd
20+
{
21+
namespace detail
22+
{
23+
template <class Arch = default_arch, class ForwardIterator, class T>
24+
T sequential_arange(ForwardIterator first, ForwardIterator last, T value, T step) noexcept
25+
{
26+
for (; first != last; ++first, value += step)
27+
{
28+
*first = value;
29+
}
30+
31+
return value;
32+
}
33+
}
34+
35+
template <class Arch = default_arch, class ContiguousIterator, class T>
36+
void arange(ContiguousIterator first, ContiguousIterator last, T value, T step) noexcept
37+
{
38+
using value_type = typename std::decay<decltype(*first)>::type;
39+
using batch_type = batch<value_type, Arch>;
40+
41+
const std::size_t size = static_cast<std::size_t>(std::distance(first, last));
42+
constexpr std::size_t simd_size = batch_type::size;
43+
44+
if (size < simd_size)
45+
{
46+
detail::sequential_arange(first, last, value, step);
47+
return;
48+
}
49+
50+
const auto* const ptr_begin = &(*first);
51+
const std::size_t align_begin = xsimd::get_alignment_offset(ptr_begin, size, simd_size);
52+
const std::size_t align_end = align_begin + ((size - align_begin) & ~(simd_size - 1));
53+
54+
const auto align_begin_it = std::next(first, align_begin);
55+
const auto align_end_it = std::next(first, align_end);
56+
57+
value = detail::sequential_arange(first, align_begin_it, value, step);
58+
59+
alignas(batch_type::arch_type::alignment()) value_type init_tmp[simd_size];
60+
detail::sequential_arange(init_tmp, init_tmp + simd_size, value, step);
61+
batch_type batch_val = batch_type::load_aligned(init_tmp);
62+
63+
const batch_type step_batch(static_cast<value_type>(simd_size));
64+
for (auto current = align_begin_it; current != align_end_it; std::advance(current, simd_size))
65+
{
66+
batch_val.store_aligned(&(*current));
67+
batch_val = batch_val + (step_batch * step);
68+
}
69+
70+
value = *std::next(align_end_it, -1) + step;
71+
72+
detail::sequential_arange(align_end_it, last, value, step);
73+
}
74+
75+
} // namespace xsimd
76+
77+
#endif // XSIMD_ALGORITHMS_ARANGE_HPP

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ endif()
4747

4848
set(XSIMD_ALGORITHM_TESTS
4949
main.cpp
50+
test_arange.cpp
5051
test_iterator.cpp
5152
test_reduce.cpp
5253
test_transform.cpp

test/test_arange.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/***************************************************************************
2+
* Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3+
* Martin Renou *
4+
* Copyright (c) QuantStack *
5+
* Copyright (c) Serge Guelton *
6+
* *
7+
* Distributed under the terms of the BSD 3-Clause License. *
8+
* *
9+
* The full license is in the file LICENSE, distributed with this software. *
10+
****************************************************************************/
11+
12+
#include "xsimd_algorithm/stl/arange.hpp"
13+
14+
#ifndef XSIMD_NO_SUPPORTED_ARCHITECTURE
15+
16+
#include "doctest/doctest.h"
17+
18+
#include <cstddef>
19+
#include <vector>
20+
21+
#if XSIMD_WITH_NEON && !XSIMD_WITH_NEON64
22+
#define ARANGE_TYPES int, float
23+
#else
24+
#define ARANGE_TYPES int, long, float, double
25+
#endif
26+
27+
template <typename Type>
28+
struct arange_test
29+
{
30+
using vector = std::vector<Type>;
31+
static constexpr std::size_t simd_size = xsimd::batch<Type>::size;
32+
33+
static vector fill_expected(Type start, size_t size, Type step = Type { 1 })
34+
{
35+
vector result(size);
36+
37+
for (size_t i = 0; i < size; ++i)
38+
{
39+
result[i] = start + (i * step);
40+
}
41+
42+
return result;
43+
}
44+
45+
void test_arange_aligned(Type init_value, size_t size, Type step) const
46+
{
47+
vector c(size);
48+
xsimd::arange(c.begin(), c.end(), init_value, step);
49+
const vector expected = fill_expected(init_value, size, step);
50+
51+
CHECK(std::equal(expected.begin(), expected.end(), c.begin()));
52+
CHECK(expected.size() == c.size());
53+
}
54+
55+
void test_arange_misaligned(Type init_value, size_t size, Type step) const
56+
{
57+
const size_t missalignment = 1;
58+
vector c(size + missalignment * 2);
59+
auto first = c.begin() + missalignment;
60+
auto last = first + size;
61+
62+
xsimd::arange(first, last, init_value, step);
63+
64+
const vector expected = fill_expected(init_value, size, step);
65+
CHECK(std::equal(expected.begin(), expected.end(), first));
66+
CHECK(expected.size() == static_cast<size_t>(std::distance(first, last)));
67+
}
68+
};
69+
70+
TEST_CASE_TEMPLATE("arange test", T, ARANGE_TYPES)
71+
{
72+
using Test = arange_test<T>;
73+
74+
const std::array test_sizes {
75+
size_t { 0 },
76+
size_t { 1 },
77+
Test::simd_size - 1,
78+
Test::simd_size,
79+
Test ::simd_size + 1,
80+
};
81+
82+
const std::array init_values {
83+
T { -1 },
84+
T { 0 },
85+
T { 1 },
86+
};
87+
88+
const std::array steps { -2, -1, 0, 1, 2 };
89+
90+
Test test;
91+
92+
size_t sub_case_id = 0;
93+
for (const auto size : test_sizes)
94+
{
95+
for (const auto init_value : init_values)
96+
{
97+
for (const auto step : steps)
98+
{
99+
const std::string aligned_subcase_name = "Aligned" + std::to_string(sub_case_id++) + ", size: " + std::to_string(size) + ", init_value: " + std::to_string(init_value) + ", step: " + std::to_string(step);
100+
SUBCASE(aligned_subcase_name.c_str())
101+
{
102+
test.test_arange_aligned(init_value, size, step);
103+
}
104+
const std::string misaligned_subcase_name = "Misaligned" + std::to_string(sub_case_id++) + ", size: " + std::to_string(size) + ", init_value: " + std::to_string(init_value) + ", step: " + std::to_string(step);
105+
SUBCASE(misaligned_subcase_name.c_str())
106+
{
107+
test.test_arange_misaligned(init_value, size, step);
108+
}
109+
}
110+
}
111+
}
112+
}
113+
114+
#endif

0 commit comments

Comments
 (0)