Skip to content

Commit af42ce7

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

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-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: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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+
using aligned_vector = std::vector<Type, xsimd::aligned_allocator<Type>>;
32+
static constexpr std::size_t simd_size = xsimd::batch<Type>::size;
33+
34+
static vector fill_expected(Type start, size_t size, Type step = Type { 1 })
35+
{
36+
vector result(size);
37+
38+
for (size_t i = 0; i < size; ++i)
39+
{
40+
result[i] = start + (i * step);
41+
}
42+
43+
return result;
44+
}
45+
46+
void test_arange_aligned(Type init_value, size_t size, Type step) const
47+
{
48+
vector c(size);
49+
xsimd::arange(c.begin(), c.end(), init_value, step);
50+
const vector expected = fill_expected(init_value, size, step);
51+
52+
CHECK(std::equal(expected.begin(), expected.end(), c.begin()));
53+
CHECK(expected.size() == c.size());
54+
}
55+
56+
void test_arange_misaligned(Type init_value, size_t size, Type step) const
57+
{
58+
const size_t missalignment = 1;
59+
vector c(size + missalignment * 2);
60+
auto first = c.begin() + missalignment;
61+
auto last = first + size;
62+
63+
xsimd::arange(first, last, init_value, step);
64+
65+
const vector expected = fill_expected(init_value, size, step);
66+
CHECK(std::equal(expected.begin(), expected.end(), first));
67+
CHECK(expected.size() == static_cast<size_t>(std::distance(first, last)));
68+
}
69+
};
70+
71+
TEST_CASE_TEMPLATE("arange test", T, ARANGE_TYPES)
72+
{
73+
using Test = arange_test<T>;
74+
75+
const std::array test_sizes {
76+
size_t { 0 },
77+
size_t { 1 },
78+
Test::simd_size - 1,
79+
Test::simd_size,
80+
Test ::simd_size + 1,
81+
};
82+
83+
const std::array init_values {
84+
T { -1 },
85+
T { 0 },
86+
T { 1 },
87+
};
88+
89+
const std::array steps { -2, -1, 0, 1, 2 };
90+
91+
Test test;
92+
93+
size_t sub_case_id = 0;
94+
for (const auto size : test_sizes)
95+
{
96+
for (const auto init_value : init_values)
97+
{
98+
for (const auto step : steps)
99+
{
100+
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);
101+
SUBCASE(aligned_subcase_name.c_str())
102+
{
103+
test.test_arange_aligned(init_value, size, step);
104+
}
105+
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);
106+
SUBCASE(misaligned_subcase_name.c_str())
107+
{
108+
test.test_arange_misaligned(init_value, size, step);
109+
}
110+
}
111+
}
112+
}
113+
}
114+
115+
#endif

0 commit comments

Comments
 (0)