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_GENERIC_LOGICAL_HPP
13#define XSIMD_GENERIC_LOGICAL_HPP
14
15#include "./xsimd_generic_details.hpp"
16
17namespace xsimd
18{
19
20 namespace kernel
21 {
22
23 using namespace types;
24
25 // from mask
26 template <class A, class T>
27 inline batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<generic>) noexcept
28 {
29 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
30 // This is inefficient but should never be called. It's just a
31 // temporary implementation until arm support is added.
32 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
33 buffer[i] = mask & (1ull << i);
34 return batch_bool<T, A>::load_aligned(buffer);
35 }
36
37 // ge
38 template <class A, class T>
39 inline batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
40 {
41 return other <= self;
42 }
43
44 // gt
45 template <class A, class T>
46 inline batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
47 {
48 return other < self;
49 }
50
51 // is_even
52 template <class A, class T>
53 inline batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<generic>) noexcept
54 {
55 return is_flint(self * T(0.5));
56 }
57
58 // is_flint
59 template <class A, class T>
60 inline batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<generic>) noexcept
61 {
62 auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self));
63 return frac == T(0.);
64 }
65
66 // is_odd
67 template <class A, class T>
68 inline batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<generic>) noexcept
69 {
70 return is_even(self - T(1.));
71 }
72
73 // isinf
74 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
75 inline batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<generic>) noexcept
76 {
77 return batch_bool<T, A>(false);
78 }
79 template <class A>
80 inline batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<generic>) noexcept
81 {
82 return abs(self) == std::numeric_limits<float>::infinity();
83 }
84 template <class A>
85 inline batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<generic>) noexcept
86 {
87 return abs(self) == std::numeric_limits<double>::infinity();
88 }
89
90 // isfinite
91 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
92 inline batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<generic>) noexcept
93 {
94 return batch_bool<T, A>(true);
95 }
96 template <class A>
97 inline batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<generic>) noexcept
98 {
99 return (self - self) == 0.f;
100 }
101 template <class A>
102 inline batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<generic>) noexcept
103 {
104 return (self - self) == 0.;
105 }
106
107 // isnan
108 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
109 inline batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<generic>) noexcept
110 {
111 return batch_bool<T, A>(false);
112 }
113
114 // le
115 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
116 inline batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
117 {
118 return (self < other) || (self == other);
119 }
120
121 // neq
122 template <class A, class T>
123 inline batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
124 {
125 return !(other == self);
126 }
127
128 // logical_and
129 template <class A, class T>
130 inline batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
131 {
132 return detail::apply([](T x, T y) noexcept
133 { return x && y; },
134 self, other);
135 }
136
137 // logical_or
138 template <class A, class T>
139 inline batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
140 {
141 return detail::apply([](T x, T y) noexcept
142 { return x || y; },
143 self, other);
144 }
145
146 // mask
147 template <class A, class T>
148 inline uint64_t mask(batch_bool<T, A> const& self, requires_arch<generic>) noexcept
149 {
150 alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
151 self.store_aligned(buffer);
152 // This is inefficient but should never be called. It's just a
153 // temporary implementation until arm support is added.
154 uint64_t res = 0;
155 for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
156 if (buffer[i])
157 res |= 1ul << i;
158 return res;
159 }
160 }
161}
162
163#endif
164