Skip to content

Commit

Permalink
never cache subelements
Browse files Browse the repository at this point in the history
  • Loading branch information
watt committed Sep 20, 2023
1 parent 0ba0e4d commit f2f03f9
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 77 deletions.
47 changes: 13 additions & 34 deletions BlueprintUI/Sources/Element/LayoutStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,40 +126,19 @@ extension LayoutStorage: LegacyContentStorage {
extension LayoutStorage: CaffeinatedContentStorage {

private func subelements(from node: LayoutTreeNode, environment: Environment) -> LayoutSubelements {
if node.sizeCache.options.assumeStableSubelements {
// Current behavior
return node.layoutSubelements {
var identifierFactory = ElementIdentifier.Factory(elementCount: children.count)
return children.map { child in
let identifier = identifierFactory.nextIdentifier(
for: type(of: child.element),
key: child.key
)
return LayoutSubelement(
identifier: identifier,
content: child.content,
environment: environment,
node: node.subnode(key: identifier),
traits: child.traits
)
}
}
} else {
// Proposed new behavior
var identifierFactory = ElementIdentifier.Factory(elementCount: children.count)
return children.map { child in
let identifier = identifierFactory.nextIdentifier(
for: type(of: child.element),
key: child.key
)
return LayoutSubelement(
identifier: identifier,
content: child.content,
environment: environment,
node: node.subnode(key: identifier),
traits: child.traits
)
}
var identifierFactory = ElementIdentifier.Factory(elementCount: children.count)
return children.map { child in
let identifier = identifierFactory.nextIdentifier(
for: type(of: child.element),
key: child.key
)
return LayoutSubelement(
identifier: identifier,
content: child.content,
environment: environment,
node: node.subnode(key: identifier),
traits: child.traits
)
}
}

Expand Down
10 changes: 0 additions & 10 deletions BlueprintUI/Sources/Internal/LayoutTreeNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ final class LayoutTreeNode {

// These commonly used properties have dedicated storage. If we need to hang more generalized
// things off this type we may want to store them in a heterogeneous dictionary.
private var _layoutSubelements: [LayoutSubelement]?
private var _associatedCache: Any?

init(path: String, signpostRef: AnyObject, options: LayoutOptions) {
Expand All @@ -48,15 +47,6 @@ final class LayoutTreeNode {
return subnode
}

func layoutSubelements(create: () -> [LayoutSubelement]) -> [LayoutSubelement] {
if let layoutSubelements = _layoutSubelements {
return layoutSubelements
}
let layoutSubelements = create()
_layoutSubelements = layoutSubelements
return layoutSubelements
}

func associatedCache<AssociatedCache>(create: () -> AssociatedCache) -> AssociatedCache {
assert(
_associatedCache is AssociatedCache?,
Expand Down
12 changes: 2 additions & 10 deletions BlueprintUI/Sources/Layout/LayoutOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ public struct LayoutOptions: Equatable {
/// The default configuration.
public static let `default` = LayoutOptions(
hintRangeBoundaries: true,
searchUnconstrainedKeys: true,
assumeStableSubelements: true
searchUnconstrainedKeys: true
)

/// Enables aggressive cache hinting along the boundaries of the range between constraints and
Expand All @@ -23,15 +22,8 @@ public struct LayoutOptions: Equatable {
/// Layout contract for correct behavior.
public var searchUnconstrainedKeys: Bool

public var assumeStableSubelements: Bool

public init(
hintRangeBoundaries: Bool,
searchUnconstrainedKeys: Bool,
assumeStableSubelements: Bool = true
) {
public init(hintRangeBoundaries: Bool, searchUnconstrainedKeys: Bool) {
self.hintRangeBoundaries = hintRangeBoundaries
self.searchUnconstrainedKeys = searchUnconstrainedKeys
self.assumeStableSubelements = assumeStableSubelements
}
}
36 changes: 13 additions & 23 deletions BlueprintUI/Tests/GeometryReaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ final class GeometryReaderTests: XCTestCase {
outerRow.addFlexible(
child: GeometryReader { geometry in

return Row { innerRow in
Row { innerRow in
innerRow.horizontalUnderflow = .growUniformly
innerRow.horizontalOverflow = .condenseUniformly
innerRow.verticalAlignment = .fill
Expand All @@ -127,32 +127,22 @@ final class GeometryReaderTests: XCTestCase {
// 4. GR body evaluates as a row with 2 children
// 5. Subelement count has changed, as well as content of child 1

LayoutMode.caffeinated(options: .notAssumingSubelementsStable).performAsDefault {
let frames = element
.layout(frame: CGRect(origin: .zero, size: size))
.queryLayout(for: Spacer.self)
.map { $0.layoutAttributes.frame }
let frames = element
.layout(frame: CGRect(origin: .zero, size: size))
.queryLayout(for: Spacer.self)
.map { $0.layoutAttributes.frame }

XCTAssertEqual(
frames,
[
CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 1, height: 120)),
CGRect(origin: CGPoint(x: 1, y: 0), size: CGSize(width: 1, height: 120)),
CGRect(origin: CGPoint(x: 85, y: 0), size: CGSize(width: 35, height: 120)),
]
)
}
XCTAssertEqual(
frames,
[
CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 1, height: 120)),
CGRect(origin: CGPoint(x: 1, y: 0), size: CGSize(width: 1, height: 120)),
CGRect(origin: CGPoint(x: 85, y: 0), size: CGSize(width: 35, height: 120)),
]
)
}
}

extension LayoutOptions {
static let notAssumingSubelementsStable = LayoutOptions(
hintRangeBoundaries: true,
searchUnconstrainedKeys: true,
assumeStableSubelements: false
)
}

extension SizeConstraint.Axis {
fileprivate var isConstrained: Bool {
switch self {
Expand Down

0 comments on commit f2f03f9

Please sign in to comment.