Skip to content

Commit 89d5325

Browse files
committed
Add PossiblyUniquePtr, a smart pointer that can dynamically store a
borrowed pointer.
1 parent 61d60eb commit 89d5325

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

include/swift/Basic/Compiler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,10 @@ inline const char *operator""_swift_u8(const char8_t *p, size_t) {
190190
#endif // defined(__cpp_char8_t)
191191
#endif // defined(__cplusplus)
192192

193+
#if __has_attribute(trivial_abi)
194+
#define SWIFT_TRIVIAL_ABI __attribute__((trivial_abi))
195+
#else
196+
#define SWIFT_TRIVIAL_ABI
197+
#endif
198+
193199
#endif // SWIFT_BASIC_COMPILER_H
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//===--- PossiblyUniquePtr.h - A dynamic smart pointer ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// This file defines PossiblyUniquePtr, a smart pointer template that
16+
/// typically owns its pointee but can dynamically just contain an unowned
17+
/// pointer.
18+
///
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef SWIFT_BASIC_POSSIBLY_UNIQUE_PTR_H
22+
#define SWIFT_BASIC_POSSIBLY_UNIQUE_PTR_H
23+
24+
#include "llvm/ADT/PointerIntPair.h"
25+
#include "swift/Basic/Compiler.h"
26+
27+
namespace swift {
28+
29+
enum PointerIsOwned_t: bool {
30+
PointerIsNotOwned = false,
31+
PointerIsOwned = true
32+
};
33+
34+
/// Essentially std::unique_ptr except it dynamically tracks whether the
35+
/// pointer is actually owned.
36+
///
37+
/// The operations which possibly transfer ownership into a PossiblyUniquePtr
38+
/// (the constructor and `reset`) privilege the owning case. This allows
39+
/// PossiblyUniquePtr<T> to serve as a drop-in replacement for
40+
/// std::unique_ptr<T>.
41+
template <class T, class PtrTraits = llvm::PointerLikeTypeTraits<T*>>
42+
class SWIFT_TRIVIAL_ABI PossiblyUniquePtr {
43+
llvm::PointerIntPair<T*, 1, bool, PtrTraits> Value;
44+
45+
// Befriend all other specializations of this class, for the use of the
46+
// converting constructor and assignment operator.
47+
template <class, class>
48+
friend class PossiblyUniquePtr;
49+
50+
public:
51+
PossiblyUniquePtr() {}
52+
53+
// Allow implicit conversion from a null pointer.
54+
PossiblyUniquePtr(std::nullptr_t) {}
55+
56+
// Require conversion from any other pointer to be explicit.
57+
explicit PossiblyUniquePtr(T *pointer,
58+
PointerIsOwned_t owned = PointerIsOwned)
59+
: Value(pointer, owned) {
60+
assert((pointer != nullptr || !owned) && "claiming ownership of null pointer");
61+
}
62+
63+
PossiblyUniquePtr(PossiblyUniquePtr &&other)
64+
: Value(other.Value) {
65+
other.dropValue();
66+
}
67+
68+
PossiblyUniquePtr &operator=(PossiblyUniquePtr &&other) {
69+
destroyValue();
70+
Value = other.Value;
71+
other.dropValue();
72+
return *this;
73+
}
74+
75+
~PossiblyUniquePtr() {
76+
destroyValue();
77+
}
78+
79+
// Converting constructor.
80+
template <class U, class UTraits>
81+
PossiblyUniquePtr(PossiblyUniquePtr<U,UTraits> &&other)
82+
: Value(other.Value.getPointer(), other.Value.getInt()) {
83+
other.dropValue();
84+
}
85+
86+
// Converting assignment operator.
87+
template <class U, class UTraits>
88+
PossiblyUniquePtr &operator=(PossiblyUniquePtr<U,UTraits> &&other) {
89+
destroyValue();
90+
Value.setPointerAndInt(other.Value.getPointer(),
91+
other.Value.getInt());
92+
other.dropValue();
93+
return *this;
94+
}
95+
96+
template <class ObjectType, class... Args>
97+
static PossiblyUniquePtr make(Args &&...args) {
98+
return PossiblyUniquePtr(new ObjectType(std::forward<Args>(args)...));
99+
}
100+
101+
/// As a unique pointer, PossiblyUniquePtr is non-copyable.
102+
PossiblyUniquePtr(const PossiblyUniquePtr &other) = delete;
103+
PossiblyUniquePtr &operator=(const PossiblyUniquePtr &other) = delete;
104+
105+
explicit operator bool() const {
106+
return Value.getPointer() != nullptr;
107+
}
108+
109+
T &operator*() const {
110+
return *get_nonnull();
111+
}
112+
T *operator->() const {
113+
return get_nonnull();
114+
}
115+
116+
/// Reset the value of this object to the given pointer.
117+
///
118+
/// Destroys the current value, if any.
119+
void reset(T *pointer = nullptr, PointerIsOwned_t owned = PointerIsOwned) & {
120+
destroyValue();
121+
Value.setPointerAndInt(pointer, owned);
122+
}
123+
124+
/// Borrow the current pointer value, leaving ownership (if any) with this object.
125+
T *get() const {
126+
return Value.getPointer();
127+
}
128+
129+
/// Borrow the current pointer value, leaving ownership (if any) with this object.
130+
/// Asserts that the pointer is non-null.
131+
T *get_nonnull() const {
132+
auto value = get();
133+
assert(value);
134+
return value;
135+
}
136+
137+
/// Determines whether this object owns its pointer value.
138+
PointerIsOwned_t isOwned() const {
139+
return PointerIsOwned_t(Value.getInt());
140+
}
141+
142+
/// Release ownership of the pointer, making the caller responsible for it.
143+
/// This can only be called on an owned pointer.
144+
T *releaseOwned() {
145+
assert(isOwned());
146+
auto value = get();
147+
dropValue();
148+
return value;
149+
}
150+
151+
private:
152+
/// Destroy the value, if we own it.
153+
void destroyValue() {
154+
if (Value.getInt()) {
155+
delete Value.getPointer();
156+
}
157+
}
158+
159+
/// Clear the stored value without asserting ownership.
160+
void dropValue() & {
161+
Value.setPointerAndInt(nullptr, 0);
162+
}
163+
};
164+
165+
template <class ObjectType, class... As>
166+
PossiblyUniquePtr<ObjectType> make_possibly_unique(As &&...args) {
167+
return PossiblyUniquePtr<ObjectType>::
168+
template make<ObjectType>(std::forward<As>(args)...);
169+
}
170+
171+
} // end namespace swift
172+
173+
#endif

0 commit comments

Comments
 (0)