1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
11 #define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
12
13 #include <__type_traits/is_assignable.h>
14 #include <__type_traits/is_same.h>
15 #include <__utility/forward.h>
16 #include <__utility/move.h>
17 #include <cstddef>
18 #include <experimental/__config>
19 #include <experimental/__simd/utility.h>
20
21 _LIBCPP_PUSH_MACROS
22 #include <__undef_macros>
23
24 #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
25
26 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
27 inline namespace parallelism_v2 {
28 template <class _Tp, class _Storage, class _Vp>
29 class __simd_reference {
30 template <class, class>
31 friend class simd;
32 template <class, class>
33 friend class simd_mask;
34
35 _Storage& __s_;
36 size_t __idx_;
37
__simd_reference(_Storage & __s,size_t __idx)38 _LIBCPP_HIDE_FROM_ABI __simd_reference(_Storage& __s, size_t __idx) : __s_(__s), __idx_(__idx) {}
39
__get()40 _LIBCPP_HIDE_FROM_ABI _Vp __get() const noexcept { return __s_.__get(__idx_); }
41
__set(_Vp __v)42 _LIBCPP_HIDE_FROM_ABI void __set(_Vp __v) {
43 if constexpr (is_same_v<_Vp, bool>)
44 __s_.__set(__idx_, experimental::__set_all_bits<_Tp>(__v));
45 else
46 __s_.__set(__idx_, __v);
47 }
48
49 public:
50 using value_type = _Vp;
51
52 __simd_reference() = delete;
53 __simd_reference(const __simd_reference&) = delete;
54
value_type()55 _LIBCPP_HIDE_FROM_ABI operator value_type() const noexcept { return __get(); }
56
57 template <class _Up, enable_if_t<is_assignable_v<value_type&, _Up&&>, int> = 0>
58 _LIBCPP_HIDE_FROM_ABI __simd_reference operator=(_Up&& __v) && noexcept {
59 __set(static_cast<value_type>(std::forward<_Up>(__v)));
60 return {__s_, __idx_};
61 }
62
63 // Note: This approach might not fully align with the specification,
64 // which might be a wording defect. (https://wg21.link/N4808 section 9.6.3)
65 template <class _Tp1, class _Storage1, class _Vp1>
66 friend void
67 swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
68
69 template <class _Tp1, class _Storage1, class _Vp1>
70 friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
71
72 template <class _Tp1, class _Storage1, class _Vp1>
73 friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
74 };
75
76 template <class _Tp, class _Storage, class _Vp>
77 _LIBCPP_HIDE_FROM_ABI void
swap(__simd_reference<_Tp,_Storage,_Vp> && __a,__simd_reference<_Tp,_Storage,_Vp> && __b)78 swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
79 _Vp __tmp(std::move(__a));
80 std::move(__a) = std::move(__b);
81 std::move(__b) = std::move(__tmp);
82 }
83
84 template <class _Tp, class _Storage, class _Vp>
swap(_Vp & __a,__simd_reference<_Tp,_Storage,_Vp> && __b)85 _LIBCPP_HIDE_FROM_ABI void swap(_Vp& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
86 _Vp __tmp(std::move(__a));
87 __a = std::move(__b);
88 std::move(__b) = std::move(__tmp);
89 }
90
91 template <class _Tp, class _Storage, class _Vp>
swap(__simd_reference<_Tp,_Storage,_Vp> && __a,_Vp & __b)92 _LIBCPP_HIDE_FROM_ABI void swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, _Vp& __b) noexcept {
93 _Vp __tmp(std::move(__a));
94 std::move(__a) = std::move(__b);
95 __b = std::move(__tmp);
96 }
97
98 } // namespace parallelism_v2
99 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
100
101 #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
102
103 _LIBCPP_POP_MACROS
104
105 #endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
106