Files
swift-mirror/utils/swift-xcodegen/Sources/SwiftXcodeGen/BuildArgs/CommandArgTree.swift
Hamish Knight abc099cfa9 [xcodegen] Match common prefix in CommandArgTree
Rather than forming a set intersection, only look for a common prefix
with the parent arguments. This is both quicker and more correct
since arguments can be order-dependent. This does mean we'll end up
with more per-file arguments for "umbrella" targets, but that at
least will no longer prevent us from forming buildable folders for
them.
2025-05-07 13:48:45 +01:00

54 lines
2.0 KiB
Swift

//===--- CommandArgTree.swift ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
/// A tree of compile command arguments, indexed by path such that those unique
/// to a particular file can be queried, with common-prefixed arguments
/// associated with a common parent.
struct CommandArgTree {
private var storage: [RelativePath: [Command.Argument]]
init() {
self.storage = [:]
}
mutating func insert(_ args: [Command.Argument], for path: RelativePath) {
for component in path.stackedComponents {
// If we haven't added any arguments, add them. If we're adding arguments
// for the file itself, this is the only way we'll add arguments,
// otherwise we can form a common prefix with the other arguments.
let inserted = storage.insertValue(args, for: component)
guard !inserted && component != path else { continue }
// We use withValue(for:default:) to mutate in-place without CoW.
storage.withValue(for: component, default: []) { existingArgs in
let slice = existingArgs.commonPrefix(with: args)
existingArgs.removeSubrange(slice.endIndex...)
}
}
}
/// Retrieve the arguments at a given path, including those in the parent.
func getArgs(for path: RelativePath) -> [Command.Argument] {
storage[path] ?? []
}
/// Retrieve the arguments at a given path, excluding those already covered
/// by a given parent.
func getUniqueArgs(
for path: RelativePath, parent: RelativePath
) -> [Command.Argument] {
let childArgs = getArgs(for: path)
let parentArgs = getArgs(for: parent)
return Array(childArgs[parentArgs.count...])
}
}