2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef POINTERUNION_H
25 #define POINTERUNION_H
32 template <typename T
> struct PointerUnionTypeSelectorReturn
{
36 /// Get a type based on whether two types are the same or not.
41 /// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
44 /// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
45 template <typename T1
, typename T2
, typename RET_EQ
, typename RET_NE
>
46 struct PointerUnionTypeSelector
{
47 using Return
= typename PointerUnionTypeSelectorReturn
<RET_NE
>::Return
;
50 template <typename T
, typename RET_EQ
, typename RET_NE
>
51 struct PointerUnionTypeSelector
<T
, T
, RET_EQ
, RET_NE
> {
52 using Return
= typename PointerUnionTypeSelectorReturn
<RET_EQ
>::Return
;
55 template <typename T1
, typename T2
, typename RET_EQ
, typename RET_NE
>
56 struct PointerUnionTypeSelectorReturn
<
57 PointerUnionTypeSelector
<T1
, T2
, RET_EQ
, RET_NE
>> {
59 typename PointerUnionTypeSelector
<T1
, T2
, RET_EQ
, RET_NE
>::Return
;
62 template <class PT1
, class PT2
>
66 static_assert(alignof(PT1
) >= 2, "alignment requirement");
67 static_assert(alignof(PT2
) >= 2, "alignment requirement");
70 static const uintptr_t Num
= 0;
73 static const uintptr_t Num
= 1;
75 template <typename T
> struct UNION_DOESNT_CONTAIN_TYPE
{};
77 uintptr_t getPointer() const {
80 uintptr_t getTag() const {
85 explicit PointerUnion(const std::atomic
<uintptr_t> &raw
)
86 : _value(raw
.load(std::memory_order_relaxed
))
88 PointerUnion(PT1 t
) : _value((uintptr_t)t
) { }
89 PointerUnion(PT2 t
) : _value((uintptr_t)t
| 1) { }
91 void storeAt(std::atomic
<uintptr_t> &raw
, std::memory_order order
) const {
92 raw
.store(_value
, order
);
97 using Ty
= typename PointerUnionTypeSelector
<PT1
, T
, IsPT1
,
98 PointerUnionTypeSelector
<PT2
, T
, IsPT2
,
99 UNION_DOESNT_CONTAIN_TYPE
<T
>>>::Return
;
100 return getTag() == Ty::Num
;
103 template <typename T
> T
get() const {
104 ASSERT(is
<T
>() && "Invalid accessor called");
105 return reinterpret_cast<T
>(getPointer());
108 template <typename T
> T
dyn_cast() const {
115 template <class PT1
, class PT2
, class PT3
, class PT4
= void>
116 class PointerUnion4
{
119 static_assert(alignof(PT1
) >= 4, "alignment requirement");
120 static_assert(alignof(PT2
) >= 4, "alignment requirement");
121 static_assert(alignof(PT3
) >= 4, "alignment requirement");
122 static_assert(alignof(PT4
) >= 4, "alignment requirement");
125 static const uintptr_t Num
= 0;
128 static const uintptr_t Num
= 1;
131 static const uintptr_t Num
= 2;
134 static const uintptr_t Num
= 3;
136 template <typename T
> struct UNION_DOESNT_CONTAIN_TYPE
{};
138 uintptr_t getPointer() const {
141 uintptr_t getTag() const {
146 explicit PointerUnion4(const std::atomic
<uintptr_t> &raw
)
147 : _value(raw
.load(std::memory_order_relaxed
))
149 PointerUnion4(PT1 t
) : _value((uintptr_t)t
) { }
150 PointerUnion4(PT2 t
) : _value((uintptr_t)t
| 1) { }
151 PointerUnion4(PT3 t
) : _value((uintptr_t)t
| 2) { }
152 PointerUnion4(PT4 t
) : _value((uintptr_t)t
| 3) { }
154 void storeAt(std::atomic
<uintptr_t> &raw
, std::memory_order order
) const {
155 raw
.store(_value
, order
);
158 template <typename T
>
160 using Ty
= typename PointerUnionTypeSelector
<PT1
, T
, IsPT1
,
161 PointerUnionTypeSelector
<PT2
, T
, IsPT2
,
162 PointerUnionTypeSelector
<PT3
, T
, IsPT3
,
163 PointerUnionTypeSelector
<PT4
, T
, IsPT4
,
164 UNION_DOESNT_CONTAIN_TYPE
<T
>>>>>::Return
;
165 return getTag() == Ty::Num
;
168 template <typename T
> T
get() const {
169 ASSERT(is
<T
>() && "Invalid accessor called");
170 return reinterpret_cast<T
>(getPointer());
173 template <typename T
> T
dyn_cast() const {
182 #endif /* DENSEMAPEXTRAS_H */