Skip to content

Commit 3e0b919

Browse files
committed
[stdlib] MemoryLayout: Add support for non-copyable type arguments
1 parent 6fbc06e commit 3e0b919

File tree

2 files changed

+105
-6
lines changed

2 files changed

+105
-6
lines changed

stdlib/public/core/MemoryLayout.swift

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -40,7 +40,9 @@
4040
/// byteCount: count * MemoryLayout<Point>.stride,
4141
/// alignment: MemoryLayout<Point>.alignment)
4242
@frozen // namespace
43-
public enum MemoryLayout<T> {
43+
public enum MemoryLayout<T: ~Copyable> {}
44+
45+
extension MemoryLayout where T: ~Copyable {
4446
/// The contiguous memory footprint of `T`, in bytes.
4547
///
4648
/// A type's size does not include any dynamically allocated or out of line
@@ -50,6 +52,7 @@ public enum MemoryLayout<T> {
5052
/// When allocating memory for multiple instances of `T` using an unsafe
5153
/// pointer, use a multiple of the type's stride instead of its size.
5254
@_transparent
55+
@_alwaysEmitIntoClient
5356
public static var size: Int {
5457
return Int(Builtin.sizeof(T.self))
5558
}
@@ -62,6 +65,7 @@ public enum MemoryLayout<T> {
6265
/// trades runtime performance for space efficiency. This value is always
6366
/// positive.
6467
@_transparent
68+
@_alwaysEmitIntoClient
6569
public static var stride: Int {
6670
return Int(Builtin.strideof(T.self))
6771
}
@@ -71,12 +75,36 @@ public enum MemoryLayout<T> {
7175
/// Use the `alignment` property for a type when allocating memory using an
7276
/// unsafe pointer. This value is always positive.
7377
@_transparent
78+
@_alwaysEmitIntoClient
7479
public static var alignment: Int {
7580
return Int(Builtin.alignof(T.self))
7681
}
7782
}
7883

7984
extension MemoryLayout {
85+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
86+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
87+
@usableFromInline
88+
internal static var size: Int {
89+
return Int(Builtin.sizeof(T.self))
90+
}
91+
92+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
93+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
94+
@usableFromInline
95+
internal static var stride: Int {
96+
return Int(Builtin.strideof(T.self))
97+
}
98+
99+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
100+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
101+
@usableFromInline
102+
internal static var alignment: Int {
103+
return Int(Builtin.alignof(T.self))
104+
}
105+
}
106+
107+
extension MemoryLayout where T: ~Copyable {
80108
/// Returns the contiguous memory footprint of the given instance.
81109
///
82110
/// The result does not include any dynamically allocated or out of line
@@ -100,7 +128,8 @@ extension MemoryLayout {
100128
/// - Parameter value: A value representative of the type to describe.
101129
/// - Returns: The size, in bytes, of the given value's type.
102130
@_transparent
103-
public static func size(ofValue value: T) -> Int {
131+
@_alwaysEmitIntoClient
132+
public static func size(ofValue value: borrowing T) -> Int {
104133
return MemoryLayout.size
105134
}
106135

@@ -128,7 +157,8 @@ extension MemoryLayout {
128157
/// - Parameter value: A value representative of the type to describe.
129158
/// - Returns: The stride, in bytes, of the given value's type.
130159
@_transparent
131-
public static func stride(ofValue value: T) -> Int {
160+
@_alwaysEmitIntoClient
161+
public static func stride(ofValue value: borrowing T) -> Int {
132162
return MemoryLayout.stride
133163
}
134164

@@ -153,10 +183,36 @@ extension MemoryLayout {
153183
/// - Returns: The default memory alignment, in bytes, of the given value's
154184
/// type. This value is always positive.
155185
@_transparent
156-
public static func alignment(ofValue value: T) -> Int {
186+
@_alwaysEmitIntoClient
187+
public static func alignment(ofValue value: borrowing T) -> Int {
157188
return MemoryLayout.alignment
158189
}
190+
}
159191

192+
extension MemoryLayout {
193+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
194+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
195+
@usableFromInline
196+
internal static func size(ofValue value: borrowing T) -> Int {
197+
return MemoryLayout.size
198+
}
199+
200+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
201+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
202+
@usableFromInline
203+
internal static func stride(ofValue value: borrowing T) -> Int {
204+
return MemoryLayout.stride
205+
}
206+
207+
// TODO: Merge this back into the noncopyable variant once we have @_preInverseGenerics
208+
@available(swift, obsoleted: 5.11) // Legacy ABI compatibility
209+
@usableFromInline
210+
internal static func alignment(ofValue value: borrowing T) -> Int {
211+
return MemoryLayout.alignment
212+
}
213+
}
214+
215+
extension MemoryLayout {
160216
/// Returns the offset of an inline stored property within a type's in-memory
161217
/// representation.
162218
///
@@ -226,12 +282,15 @@ extension MemoryLayout {
226282
@_transparent
227283
@_unavailableInEmbedded
228284
public static func offset(of key: PartialKeyPath<T>) -> Int? {
285+
// FIXME(noncopyableGenerics): The new (implicit) `where T: Copyable`
286+
// extension constraint currently changes the mangling of this from a
287+
// standalone function to an extension method.
229288
return key._storedInlineOffset
230289
}
231290
}
232291

233292
// Not-yet-public alignment conveniences
234-
extension MemoryLayout {
293+
extension MemoryLayout where T: ~Copyable {
235294
internal static var _alignmentMask: Int { return alignment - 1 }
236295

237296
internal static func _roundingUpToAlignment(_ value: Int) -> Int {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-run-simple-swift(-enable-experimental-feature NoncopyableGenerics) | %FileCheck %s
3+
// REQUIRES: executable_test, noncopyable_generics
4+
5+
struct A: ~Copyable {
6+
let value: Int
7+
8+
init(_ value: Int) { self.value = value }
9+
}
10+
11+
let expectedSize = MemoryLayout<Int>.size
12+
let expectedStride = MemoryLayout<Int>.stride
13+
let expectedAlignment = MemoryLayout<Int>.alignment
14+
15+
16+
let actualSize1 = MemoryLayout<A>.size
17+
// CHECK: size: true
18+
print("size: \(actualSize1 == expectedSize)")
19+
20+
let actualStride1 = MemoryLayout<A>.stride
21+
// CHECK: stride: true
22+
print("stride: \(actualStride1 == expectedStride)")
23+
24+
let actualAlignment1 = MemoryLayout<A>.alignment
25+
// CHECK: alignment: true
26+
print("alignment: \(actualAlignment1 == expectedAlignment)")
27+
28+
let a = A(42)
29+
30+
let actualSize2 = MemoryLayout.size(ofValue: a)
31+
// CHECK: size(ofValue:): true
32+
print("size(ofValue:): \(actualSize2 == expectedSize)")
33+
34+
let actualStride2 = MemoryLayout.stride(ofValue: a)
35+
// CHECK: stride(ofValue:): true
36+
print("stride(ofValue:): \(actualStride2 == expectedStride)")
37+
38+
let actualAlignment2 = MemoryLayout.alignment(ofValue: a)
39+
// CHECK: alignment(ofValue:): true
40+
print("alignment(ofValue:): \(actualAlignment2 == expectedAlignment)")

0 commit comments

Comments
 (0)