Skip to content

Commit 353eb9f

Browse files
KeyPath offset tests were breaking on Ubuntu 20.04. It's possible _storedInlineOffset wasn't factored out correctly.
1 parent 5efc87c commit 353eb9f

File tree

1 file changed

+46
-17
lines changed

1 file changed

+46
-17
lines changed

stdlib/public/core/KeyPath.swift

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,15 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
199199
return false
200200
}
201201

202+
// TODO: Merge the functionality of _computeOffsetForPureStructKeypath,
203+
// _recalculateOffsetForPureStructKeyPath() and _storedInlineOffset.
204+
202205
// If this keypath traverses structs only, it'll have a predictable memory layout.
203206
// We can then jump to the value directly in _projectReadOnly().
204-
internal func _computeOffsets() -> (offset: Int, isPureStruct: Bool, isTuple: Bool) {
207+
internal func _computeOffsetForPureStructKeypath() {
205208
_pureStructValueOffset = 0
206209
var isPureStruct = true
207-
var _isTuple = false
210+
var exitEarly = false
208211
defer {
209212
_isPureStructKeyPath = isPureStruct
210213
}
@@ -215,43 +218,69 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
215218
isPureStruct = false
216219
}
217220
} else {
218-
while true {
221+
while !exitEarly {
219222
let (rawComponent, optNextType) = buffer.next()
220223
if isTuple(optNextType as Any) {
221224
isPureStruct = false
222-
_isTuple = true
225+
break
223226
}
224227
switch rawComponent.header.kind {
225228
case .struct:
226229
_pureStructValueOffset += rawComponent._structOrClassOffset
227230
case .class, .computed, .optionalChain, .optionalForce, .optionalWrap, .external:
228231
isPureStruct = false
232+
exitEarly = true
229233
}
230234
if optNextType == nil {
231235
break
232236
}
233237
}
234238
}
235239
}
236-
return (_pureStructValueOffset, isPureStruct, _isTuple)
237240
}
238241

239-
internal func _computeOffsetForPureStructKeypath() {
240-
_ = _computeOffsets()
242+
// Recalculates the offset in the case where one pure struct keypath is appended to another.
243+
internal func _recalculateOffsetForPureStructKeyPath() {
244+
_pureStructValueOffset = 0
245+
withBuffer {
246+
var buffer = $0
247+
while true {
248+
let (rawComponent, optNextType) = buffer.next()
249+
switch rawComponent.header.kind {
250+
case .struct:
251+
_pureStructValueOffset += rawComponent._structOrClassOffset
252+
case .class, .computed, .optionalChain, .optionalForce, .optionalWrap, .external:
253+
return
254+
}
255+
if optNextType == nil {
256+
break
257+
}
258+
}
259+
}
241260
}
242261

243-
// This function was refactored since _computeOffsets() was performing
244-
// essentially the same computation.
245262
@usableFromInline // Exposed as public API by MemoryLayout<Root>.offset(of:)
246263
internal var _storedInlineOffset: Int? {
247-
// TODO: Cache this value in a similar manner to _pureStructValueOffset.
248-
// The current design assumes keypath read and write operations will be called
249-
// much more often than MemoryLayout<Root>.offset(of:).
250-
let offsetInformation = _computeOffsets()
251-
if offsetInformation.isPureStruct || offsetInformation.isTuple {
252-
return .some(offsetInformation.offset)
253-
} else {
254-
return .none
264+
return withBuffer {
265+
var buffer = $0
266+
267+
// The identity key path is effectively a stored keypath of type Self
268+
// at offset zero
269+
if buffer.data.isEmpty { return 0 }
270+
271+
var offset = 0
272+
while true {
273+
let (rawComponent, optNextType) = buffer.next()
274+
switch rawComponent.header.kind {
275+
case .struct:
276+
offset += rawComponent._structOrClassOffset
277+
278+
case .class, .computed, .optionalChain, .optionalForce, .optionalWrap, .external:
279+
return .none
280+
}
281+
282+
if optNextType == nil { return .some(offset) }
283+
}
255284
}
256285
}
257286
}

0 commit comments

Comments
 (0)