Skip to content
This repository was archived by the owner on Mar 22, 2023. It is now read-only.

Commit faaa260

Browse files
igchorJanDorniak99
authored andcommitted
Make radix_tree::tagged_ptr a generic pointer
1 parent 4745d68 commit faaa260

1 file changed

Lines changed: 215 additions & 0 deletions

File tree

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
/* Copyright 2021, Intel Corporation */
3+
4+
#ifndef LIBPMEMOBJ_CPP_TAGGED_PTR
5+
#define LIBPMEMOBJ_CPP_TAGGED_PTR
6+
7+
#include <cassert>
8+
9+
#include <libpmemobj++/experimental/atomic_self_relative_ptr.hpp>
10+
#include <libpmemobj++/experimental/self_relative_ptr.hpp>
11+
#include <libpmemobj++/persistent_ptr.hpp>
12+
13+
namespace pmem
14+
{
15+
namespace detail
16+
{
17+
18+
template <typename P1, typename P2, typename PointerType>
19+
struct tagged_ptr_impl {
20+
tagged_ptr_impl() = default;
21+
tagged_ptr_impl(const tagged_ptr_impl &rhs) = default;
22+
23+
tagged_ptr_impl(std::nullptr_t) : ptr(nullptr)
24+
{
25+
assert(!(bool)*this);
26+
}
27+
28+
tagged_ptr_impl(const obj::persistent_ptr<P1> &ptr)
29+
: ptr(add_tag(ptr.get()))
30+
{
31+
assert(get<P1>() == ptr.get());
32+
}
33+
34+
tagged_ptr_impl(const obj::persistent_ptr<P2> &ptr) : ptr(ptr.get())
35+
{
36+
assert(get<P2>() == ptr.get());
37+
}
38+
39+
tagged_ptr_impl &operator=(const tagged_ptr_impl &rhs) = default;
40+
41+
tagged_ptr_impl &operator=(std::nullptr_t)
42+
{
43+
ptr = nullptr;
44+
assert(!(bool)*this);
45+
46+
return *this;
47+
}
48+
tagged_ptr_impl &
49+
operator=(const obj::persistent_ptr<P1> &rhs)
50+
{
51+
ptr = add_tag(rhs.get());
52+
assert(get<P1>() == rhs.get());
53+
54+
return *this;
55+
}
56+
tagged_ptr_impl &
57+
operator=(const obj::persistent_ptr<P2> &rhs)
58+
{
59+
ptr = rhs.get();
60+
assert(get<P2>() == rhs.get());
61+
62+
return *this;
63+
}
64+
65+
bool
66+
operator==(const tagged_ptr_impl &rhs) const
67+
{
68+
return ptr.to_byte_pointer() == rhs.ptr.to_byte_pointer();
69+
}
70+
bool
71+
operator!=(const tagged_ptr_impl &rhs) const
72+
{
73+
return !(*this == rhs);
74+
}
75+
76+
bool
77+
operator==(const P1 *rhs) const
78+
{
79+
return is_tagged() && get<P1>() == rhs;
80+
}
81+
82+
bool
83+
operator!=(const P2 *rhs) const
84+
{
85+
return !(*this == rhs);
86+
}
87+
88+
void
89+
swap(tagged_ptr_impl &rhs)
90+
{
91+
ptr.swap(rhs.ptr);
92+
}
93+
94+
template <typename T>
95+
typename std::enable_if<std::is_same<T, P1>::value, bool>::type
96+
is() const
97+
{
98+
return is_tagged();
99+
}
100+
101+
template <typename T>
102+
typename std::enable_if<!std::is_same<T, P1>::value, bool>::type
103+
is() const
104+
{
105+
return !is_tagged();
106+
}
107+
108+
template <typename T>
109+
typename std::enable_if<std::is_same<T, P1>::value, T *>::type
110+
get() const
111+
{
112+
assert(is_tagged());
113+
return static_cast<P1 *>(remove_tag(ptr.to_void_pointer()));
114+
}
115+
116+
template <typename T>
117+
typename std::enable_if<!std::is_same<T, P1>::value, T *>::type
118+
get() const
119+
{
120+
assert(!is_tagged());
121+
return static_cast<P2 *>(ptr.to_void_pointer());
122+
}
123+
124+
P2 *operator->() const
125+
{
126+
return get<P2>();
127+
}
128+
129+
explicit operator bool() const noexcept
130+
{
131+
return remove_tag(ptr.to_void_pointer()) != nullptr;
132+
}
133+
134+
private:
135+
static constexpr uintptr_t IS_TAGGED = 1;
136+
void *
137+
add_tag(P1 *ptr) const
138+
{
139+
auto tagged =
140+
reinterpret_cast<uintptr_t>(ptr) | uintptr_t(IS_TAGGED);
141+
return reinterpret_cast<P1 *>(tagged);
142+
}
143+
144+
void *
145+
remove_tag(void *ptr) const
146+
{
147+
auto untagged = reinterpret_cast<uintptr_t>(ptr) &
148+
~uintptr_t(IS_TAGGED);
149+
return reinterpret_cast<void *>(untagged);
150+
}
151+
152+
bool
153+
is_tagged() const
154+
{
155+
auto value = reinterpret_cast<uintptr_t>(ptr.to_void_pointer());
156+
return value & uintptr_t(IS_TAGGED);
157+
}
158+
159+
PointerType ptr;
160+
};
161+
162+
template <typename P1, typename P2>
163+
using tagged_ptr =
164+
tagged_ptr_impl<P1, P2, obj::experimental::self_relative_ptr<void>>;
165+
166+
} /* namespace detail */
167+
} /* namespace pmem */
168+
169+
namespace std
170+
{
171+
172+
template <typename P1, typename P2>
173+
struct atomic<pmem::detail::tagged_ptr<P1, P2>> {
174+
private:
175+
using ptr_type = pmem::detail::tagged_ptr_impl<
176+
P1, P2,
177+
std::atomic<pmem::obj::experimental::self_relative_ptr<void>>>;
178+
179+
public:
180+
using this_type = atomic;
181+
using value_type = pmem::detail::tagged_ptr<P1, P2>;
182+
183+
/*
184+
* Constructors
185+
*/
186+
constexpr atomic() noexcept = default;
187+
atomic(value_type value) : ptr()
188+
{
189+
store(value);
190+
}
191+
atomic(const atomic &) = delete;
192+
193+
void
194+
store(value_type desired,
195+
std::memory_order order = std::memory_order_seq_cst) noexcept
196+
{
197+
LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr);
198+
ptr.store(desired, order);
199+
}
200+
201+
value_type
202+
load(std::memory_order order = std::memory_order_seq_cst) const noexcept
203+
{
204+
auto ptr = this->ptr.load(order);
205+
LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, &ptr);
206+
return ptr;
207+
}
208+
209+
private:
210+
ptr_type ptr;
211+
};
212+
213+
} /* namespace std */
214+
215+
#endif /* LIBPMEMOBJ_CPP_TAGGED_PTR */

0 commit comments

Comments
 (0)