Skip to content

Commit 15a0f25

Browse files
committed
Factor out unsafe stuff into _Pointer extensions
1 parent 8fec025 commit 15a0f25

File tree

4 files changed

+282
-401
lines changed

4 files changed

+282
-401
lines changed

stdlib/public/core/BridgeObjectiveC.swift

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -493,14 +493,51 @@ public struct AutoreleasingUnsafeMutablePointer<Pointee /* TODO : class */>
493493
}
494494
}
495495

496-
extension AutoreleasingUnsafeMutablePointer: Equatable {
497-
@inlinable // FIXME(sil-serialize-all)
498-
@_transparent
499-
public static func == (
500-
lhs: AutoreleasingUnsafeMutablePointer,
501-
rhs: AutoreleasingUnsafeMutablePointer
502-
) -> Bool {
503-
return Bool(Builtin.cmp_eq_RawPointer(lhs._rawValue, rhs._rawValue))
496+
extension AutoreleasingUnsafeMutablePointer /*: Strideable*/ {
497+
/// Returns the distance from this pointer to the given pointer, counted as
498+
/// instances of the pointer's `Pointee` type.
499+
///
500+
/// With pointers `p` and `q`, the result of `p.distance(to: q)` is
501+
/// equivalent to `q - p`.
502+
///
503+
/// Typed pointers are required to be properly aligned for their `Pointee`
504+
/// type. Proper alignment ensures that the result of `distance(to:)`
505+
/// accurately measures the distance between the two pointers, counted in
506+
/// strides of `Pointee`. To find the distance in bytes between two
507+
/// pointers, convert them to `UnsafeRawPointer` instances before calling
508+
/// `distance(to:)`.
509+
///
510+
/// - Parameter end: The pointer to calculate the distance to.
511+
/// - Returns: The distance from this pointer to `end`, in strides of the
512+
/// pointer's `Pointee` type. To access the stride, use
513+
/// `MemoryLayout<Pointee>.stride`.
514+
@inlinable
515+
public func distance(to end: AutoreleasingUnsafeMutablePointer) -> Int {
516+
return
517+
Int(Builtin.sub_Word(Builtin.ptrtoint_Word(end._rawValue),
518+
Builtin.ptrtoint_Word(_rawValue)))
519+
/ MemoryLayout<Pointee>.stride
520+
}
521+
522+
/// Returns a pointer offset from this pointer by the specified number of
523+
/// instances.
524+
///
525+
/// With pointer `p` and distance `n`, the result of `p.advanced(by: n)` is
526+
/// equivalent to `p + n`.
527+
///
528+
/// The resulting pointer must be within the bounds of the same allocation as
529+
/// this pointer.
530+
///
531+
/// - Parameter n: The number of strides of the pointer's `Pointee` type to
532+
/// offset this pointer. To access the stride, use
533+
/// `MemoryLayout<Pointee>.stride`. `n` may be positive, negative, or
534+
/// zero.
535+
/// - Returns: A pointer offset from this pointer by `n` instances of the
536+
/// `Pointee` type.
537+
@inlinable
538+
public func advanced(by n: Int) -> AutoreleasingUnsafeMutablePointer {
539+
return AutoreleasingUnsafeMutablePointer(Builtin.gep_Word(
540+
self._rawValue, n._builtinWordValue, Pointee.self))
504541
}
505542
}
506543

@@ -552,14 +589,6 @@ extension UnsafeRawPointer {
552589
}
553590
}
554591

555-
extension AutoreleasingUnsafeMutablePointer : CustomDebugStringConvertible {
556-
/// A textual representation of `self`, suitable for debugging.
557-
@inlinable
558-
public var debugDescription: String {
559-
return _rawPointerToString(_rawValue)
560-
}
561-
}
562-
563592
@_fixed_layout
564593
@usableFromInline
565594
internal struct _CocoaFastEnumerationStackBuf {

stdlib/public/core/Pointer.swift

Lines changed: 233 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,246 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
/// A stdlib-internal protocol modeled by the intrinsic pointer types,
14-
/// UnsafeMutablePointer, UnsafePointer, and
15-
/// AutoreleasingUnsafeMutablePointer.
16-
public protocol _Pointer {
14+
/// UnsafeMutablePointer, UnsafePointer, UnsafeRawPointer,
15+
/// UnsafeMutableRawPointer, and AutoreleasingUnsafeMutablePointer.
16+
public protocol _Pointer
17+
: Hashable, Strideable, CustomDebugStringConvertible, CustomReflectable {
18+
/// A type that represents the distance between two pointers.
19+
typealias Distance = Int
20+
21+
associatedtype Pointee
22+
1723
/// The underlying raw pointer value.
1824
var _rawValue: Builtin.RawPointer { get }
1925

2026
/// Creates a pointer from a raw value.
2127
init(_ _rawValue: Builtin.RawPointer)
2228
}
2329

30+
extension _Pointer {
31+
/// Creates a new typed pointer from the given opaque pointer.
32+
///
33+
/// - Parameter from: The opaque pointer to convert to a typed pointer.
34+
@inlinable // FIXME(sil-serialize-all)
35+
@_transparent
36+
public init(_ from : OpaquePointer) {
37+
self.init(from._rawValue)
38+
}
39+
40+
/// Creates a new typed pointer from the given opaque pointer.
41+
///
42+
/// - Parameter from: The opaque pointer to convert to a typed pointer. If
43+
/// `from` is `nil`, the result of this initializer is `nil`.
44+
@inlinable // FIXME(sil-serialize-all)
45+
@_transparent
46+
public init?(_ from : OpaquePointer?) {
47+
guard let unwrapped = from else { return nil }
48+
self.init(unwrapped)
49+
}
50+
51+
/// Creates a new pointer from the given address, specified as a bit
52+
/// pattern.
53+
///
54+
/// The address passed as `bitPattern` must have the correct alignment for
55+
/// the pointer's `Pointee` type. That is,
56+
/// `bitPattern % MemoryLayout<Pointee>.alignment` must be `0`.
57+
///
58+
/// - Parameter bitPattern: A bit pattern to use for the address of the new
59+
/// pointer. If `bitPattern` is zero, the result is `nil`.
60+
@inlinable // FIXME(sil-serialize-all)
61+
@_transparent
62+
public init?(bitPattern: Int) {
63+
if bitPattern == 0 { return nil }
64+
self.init(Builtin.inttoptr_Word(bitPattern._builtinWordValue))
65+
}
66+
67+
/// Creates a new pointer from the given address, specified as a bit
68+
/// pattern.
69+
///
70+
/// The address passed as `bitPattern` must have the correct alignment for
71+
/// the pointer's `Pointee` type. That is,
72+
/// `bitPattern % MemoryLayout<Pointee>.alignment` must be `0`.
73+
///
74+
/// - Parameter bitPattern: A bit pattern to use for the address of the new
75+
/// pointer. If `bitPattern` is zero, the result is `nil`.
76+
@inlinable // FIXME(sil-serialize-all)
77+
@_transparent
78+
public init?(bitPattern: UInt) {
79+
if bitPattern == 0 { return nil }
80+
self.init(Builtin.inttoptr_Word(bitPattern._builtinWordValue))
81+
}
82+
83+
/// Creates a new pointer from the given pointer.
84+
///
85+
/// - Parameter other: The typed pointer to convert.
86+
@inlinable // FIXME(sil-serialize-all)
87+
@_transparent
88+
public init(_ other: Self) {
89+
self.init(other._rawValue)
90+
}
91+
92+
/// Creates a new pointer from the given pointer.
93+
///
94+
/// - Parameter other: The typed pointer to convert. If `other` is `nil`, the
95+
/// result is `nil`.
96+
@inlinable // FIXME(sil-serialize-all)
97+
@_transparent
98+
public init?(_ other: Self?) {
99+
guard let unwrapped = other else { return nil }
100+
self.init(unwrapped._rawValue)
101+
}
102+
}
103+
104+
// well, this is pretty annoying
105+
extension _Pointer /*: Equatable */ {
106+
// - Note: This may be more efficient than Strideable's implementation
107+
// calling ${Self}.distance().
108+
/// Returns a Boolean value indicating whether two pointers are equal.
109+
///
110+
/// - Parameters:
111+
/// - lhs: A pointer.
112+
/// - rhs: Another pointer.
113+
/// - Returns: `true` if `lhs` and `rhs` reference the same memory address;
114+
/// otherwise, `false`.
115+
@inlinable // FIXME(sil-serialize-all)
116+
@_transparent
117+
public static func == (lhs: Self, rhs: Self) -> Bool {
118+
return Bool(Builtin.cmp_eq_RawPointer(lhs._rawValue, rhs._rawValue))
119+
}
120+
}
121+
122+
extension _Pointer /*: Comparable */ {
123+
// - Note: This is an unsigned comparison unlike Strideable's
124+
// implementation.
125+
/// Returns a Boolean value indicating whether the first pointer references
126+
/// an earlier memory location than the second pointer.
127+
///
128+
/// - Parameters:
129+
/// - lhs: A pointer.
130+
/// - rhs: Another pointer.
131+
/// - Returns: `true` if `lhs` references a memory address earlier than
132+
/// `rhs`; otherwise, `false`.
133+
@inlinable // FIXME(sil-serialize-all)
134+
@_transparent
135+
public static func < (lhs: Self, rhs: Self) -> Bool {
136+
return Bool(Builtin.cmp_ult_RawPointer(lhs._rawValue, rhs._rawValue))
137+
}
138+
}
139+
140+
/*
141+
This should be possible but currently segfaulting the compiler:
142+
extension _Pointer /*: Strideable*/ {
143+
/// Returns the distance from this pointer to the given pointer, counted as
144+
/// instances of the pointer's `Pointee` type.
145+
///
146+
/// With pointers `p` and `q`, the result of `p.distance(to: q)` is
147+
/// equivalent to `q - p`.
148+
///
149+
/// Typed pointers are required to be properly aligned for their `Pointee`
150+
/// type. Proper alignment ensures that the result of `distance(to:)`
151+
/// accurately measures the distance between the two pointers, counted in
152+
/// strides of `Pointee`. To find the distance in bytes between two
153+
/// pointers, convert them to `UnsafeRawPointer` instances before calling
154+
/// `distance(to:)`.
155+
///
156+
/// - Parameter end: The pointer to calculate the distance to.
157+
/// - Returns: The distance from this pointer to `end`, in strides of the
158+
/// pointer's `Pointee` type. To access the stride, use
159+
/// `MemoryLayout<Pointee>.stride`.
160+
@inlinable
161+
public func distance(to end: AutoreleasingUnsafeMutablePointer) -> Int {
162+
return
163+
Int(Builtin.sub_Word(Builtin.ptrtoint_Word(end._rawValue),
164+
Builtin.ptrtoint_Word(_rawValue)))
165+
/ MemoryLayout<Pointee>.stride
166+
}
167+
168+
/// Returns a pointer offset from this pointer by the specified number of
169+
/// instances.
170+
///
171+
/// With pointer `p` and distance `n`, the result of `p.advanced(by: n)` is
172+
/// equivalent to `p + n`.
173+
///
174+
/// The resulting pointer must be within the bounds of the same allocation as
175+
/// this pointer.
176+
///
177+
/// - Parameter n: The number of strides of the pointer's `Pointee` type to
178+
/// offset this pointer. To access the stride, use
179+
/// `MemoryLayout<Pointee>.stride`. `n` may be positive, negative, or
180+
/// zero.
181+
/// - Returns: A pointer offset from this pointer by `n` instances of the
182+
/// `Pointee` type.
183+
@inlinable
184+
public func advanced(by n: Int) -> AutoreleasingUnsafeMutablePointer {
185+
return AutoreleasingUnsafeMutablePointer(Builtin.gep_Word(
186+
self._rawValue, n._builtinWordValue, Pointee.self))
187+
}
188+
}
189+
*/
190+
191+
extension _Pointer /*: Hashable */ {
192+
/// Hashes the essential components of this value by feeding them into the
193+
/// given hasher.
194+
///
195+
/// - Parameter hasher: The hasher to use when combining the components
196+
/// of this instance.
197+
@inlinable
198+
public func hash(into hasher: inout Hasher) {
199+
hasher.combine(Int(bitPattern: self))
200+
}
201+
}
202+
203+
extension _Pointer /*: CustomDebugStringConvertible */ {
204+
/// A textual representation of the pointer, suitable for debugging.
205+
public var debugDescription: String {
206+
return _rawPointerToString(_rawValue)
207+
}
208+
}
209+
210+
extension _Pointer /*: CustomReflectable */ {
211+
public var customMirror: Mirror {
212+
let ptrValue = UInt64(
213+
bitPattern: Int64(Int(Builtin.ptrtoint_Word(_rawValue))))
214+
return Mirror(self, children: ["pointerValue": ptrValue])
215+
}
216+
}
217+
218+
extension Int {
219+
/// Creates a new value with the bit pattern of the given pointer.
220+
///
221+
/// The new value represents the address of the pointer passed as `pointer`.
222+
/// If `pointer` is `nil`, the result is `0`.
223+
///
224+
/// - Parameter pointer: The pointer to use as the source for the new
225+
/// integer.
226+
@inlinable
227+
public init<P: _Pointer>(bitPattern pointer: P?) {
228+
if let pointer = pointer {
229+
self = Int(Builtin.ptrtoint_Word(pointer._rawValue))
230+
} else {
231+
self = 0
232+
}
233+
}
234+
}
235+
236+
extension UInt {
237+
/// Creates a new value with the bit pattern of the given pointer.
238+
///
239+
/// The new value represents the address of the pointer passed as `pointer`.
240+
/// If `pointer` is `nil`, the result is `0`.
241+
///
242+
/// - Parameter pointer: The pointer to use as the source for the new
243+
/// integer.
244+
@inlinable
245+
public init<P: _Pointer>(bitPattern pointer: P?) {
246+
if let pointer = pointer {
247+
self = UInt(Builtin.ptrtoint_Word(pointer._rawValue))
248+
} else {
249+
self = 0
250+
}
251+
}
252+
}
253+
24254
/// Derive a pointer argument from a convertible pointer type.
25255
@inlinable // FIXME(sil-serialize-all)
26256
@_transparent

0 commit comments

Comments
 (0)