Files
sourcekit-lsp/Sources/CompletionScoringTestSupport/RepeatableRandomNumberGenerator.swift
T
Rintaro Ishizaki b9e4c67793 Delete SwiftExtensions duplicates of swift-tools-protocols APIs
Delete `Collection+Only.swift`, `Duration+Seconds.swift`,
`FileManagerExtensions.swift`, `PipeAsStringHandler.swift`, and
`URLExtensions.swift` from `Sources/SwiftExtensions/`. The same
APIs now live in swift-tools-protocols as `@_spi(SourceKitLSP)
public` declarations.

Update each call site to add `@_spi(SourceKitLSP) import
ToolsProtocolsSwiftExtensions` next to the existing
`import SwiftExtensions`. Add the
`_ToolsProtocolsSwiftExtensionsForPlugin` dependency and the
`ToolsProtocolsSwiftExtensions=_ToolsProtocolsSwiftExtensionsForPlugin`
module alias to the `SwiftSourceKitClientPlugin` target in both
`Package.swift` and the corresponding `CMakeLists.txt`.
2026-06-08 21:08:24 -07:00

130 lines
4.4 KiB
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
//
//===----------------------------------------------------------------------===//
import CompletionScoring
import Foundation
import SwiftExtensions
@_spi(SourceKitLSP) import ToolsProtocolsSwiftExtensions
package struct RepeatableRandomNumberGenerator: RandomNumberGenerator {
private let seed: [UInt64]
private static let startIndex = (0, 1, 2, 3)
private var nextIndex = Self.startIndex
package init() {
self.seed = try! PropertyListDecoder().decode(
[UInt64].self,
from: loadTestResource(name: "RandomSeed", withExtension: "plist")
)
}
@discardableResult
func increment(value: inout Int, range: Range<Int>) -> Bool {
value += 1
let wrapped = (value == range.upperBound)
if wrapped {
value = range.lowerBound
}
return wrapped
}
mutating func advance() {
// This iterates through "K choose N" or "seed.count choose 4" unique combinations of 4 seed indexes. Given 1024 values in seed, that produces 45,545,029,376 unique combination of the values.
if increment(value: &nextIndex.3, range: (nextIndex.2 + 1)..<(seed.count - 0)) {
if increment(value: &nextIndex.2, range: (nextIndex.1 + 1)..<(seed.count - 1)) {
if increment(value: &nextIndex.1, range: (nextIndex.0 + 1)..<(seed.count - 2)) {
if increment(value: &nextIndex.0, range: 0..<(seed.count - 3)) {
nextIndex = Self.startIndex
return
}
nextIndex.1 = (nextIndex.0 + 1)
}
nextIndex.2 = (nextIndex.1 + 1)
}
nextIndex.3 = (nextIndex.2 + 1)
}
}
package mutating func next() -> UInt64 {
let result = seed[nextIndex.0] ^ seed[nextIndex.1] ^ seed[nextIndex.2] ^ seed[nextIndex.3]
advance()
return result
}
static func generateSeed() {
let numbers: [UInt64] = (0..<1024).map { _ in
let lo = UInt64.random(in: 0...UInt64.max)
let hi = UInt64.random(in: 0...UInt64.max)
return (hi << 32) | lo
}
let header =
"""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
"""
let body = numbers.map { number in " <integer>\(number)</integer>" }
let footer =
"""
</array>
</plist>
"""
print(([header] + body + [footer]).joined(separator: "\n"))
}
package mutating func randomLowercaseASCIIString(lengthRange: ClosedRange<Int>) -> String {
let length = lengthRange.randomElement(using: &self)
let utf8Bytes = (0..<length).map { _ in
UTF8Byte.lowercaseAZ.randomElement(using: &self)
}
return String(bytes: utf8Bytes, encoding: .utf8).unwrap(orFail: "ASCII strings are always valid UTF8 sequences")
}
package mutating func randomLowercaseASCIIStrings(
countRange: ClosedRange<Int>,
lengthRange: ClosedRange<Int>
) -> [String] {
let count = countRange.randomElement(using: &self)
var strings: [String] = []
for _ in (0..<count) {
strings.append(randomLowercaseASCIIString(lengthRange: lengthRange))
}
return strings
}
}
/// The path to the INPUTS directory of shared test projects.
private let skTestSupportInputsDirectory: URL = {
guard let resourceURL = Bundle.module.resourceURL else {
fatalError("could not determine resource URL for bundle: \(Bundle.module)")
}
guard FileManager.default.fileExists(at: resourceURL) else {
fatalError("missing resources \(resourceURL)")
}
return resourceURL.appending(components: "INPUTS", directoryHint: .isDirectory).standardizedFileURL
}()
func loadTestResource(name: String, withExtension ext: String) throws -> Data {
let file =
skTestSupportInputsDirectory
.appending(component: "\(name).\(ext)")
return try Data(contentsOf: file)
}
extension ClosedRange {
func randomElement<Generator: RandomNumberGenerator>(using randomness: inout Generator) -> Element {
return randomElement(using: &randomness)! // Closed ranges always have a value
}
}