File: ContentCache.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (108 lines) | stat: -rw-r--r-- 4,894 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 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 Swift project authors
*/

extension DocumentationContext {
    /// A cache for symbol and page content.
    ///
    /// The context uses this cache type with different values for both local content (``DocumentationContext/LocalCache``) and external content (``DocumentationContext/ExternalCache``).
    ///
    /// > Note:
    /// > The cache is not thread-safe. It's safe to read from the cache concurrently but writing needs to happen with exclusive access. It is the callers responsibility to synchronize write access.
    struct ContentCache<Value> {
        /// The main storage of cached values.
        private(set) var valuesByReference = [ResolvedTopicReference: Value]()
        /// A supplementary lookup of references by their symbol ID.
        ///
        /// If a reference is found, ``valuesByReference``  will also have a value for that reference because ``add(_:reference:symbolID:)`` is the only place that writes to this lookup and it always adds the reference-value pair to ``valuesByReference``.
        private(set) var referencesBySymbolID = [String: ResolvedTopicReference]()
        
        /// Accesses the value for a given reference.
        /// - Parameter reference: The reference to find in the cache.
        subscript(reference: ResolvedTopicReference) -> Value? {
            // Avoid copying the values if possible
            _read { yield valuesByReference[reference] }
            _modify { yield &valuesByReference[reference] }
        }
        
        /// Adds a value to the cache for a given reference _and_ symbol ID.
        /// - Parameters:
        ///   - value: The value to add to the cache.
        ///   - reference: The reference associated with that value.
        ///   - symbolID: The symbol ID associated with that value.
        mutating func add(_ value: Value, reference: ResolvedTopicReference, symbolID: String) {
            referencesBySymbolID[symbolID] = reference
            valuesByReference[reference] = value
        }
        
        /// Accesses the reference for a given symbol ID.
        /// - Parameter symbolID: The symbol ID to find in the cache.
        func reference(symbolID: String) -> ResolvedTopicReference? {
            referencesBySymbolID[symbolID]
        }
        
        /// Accesses the value for a given symbol ID.
        /// - Parameter symbolID: The symbol ID to find in the cache.
        subscript(symbolID: String) -> Value? {
            // Avoid copying the values if possible
            _read { yield referencesBySymbolID[symbolID].map { valuesByReference[$0]! } }
        }
        
        /// Reserves enough space to store the specified number of values and symbol IDs.
        ///
        /// If you are adding a known number of values pairs to a cache, use this method to avoid multiple reallocations.
        ///
        /// > Note: The cache reserves the specified capacity for both values and symbol IDs.
        ///
        /// - Parameter minimumCapacity: The requested number of key-value pairs to store.
        mutating func reserveCapacity(_ minimumCapacity: Int) {
            valuesByReference.reserveCapacity(minimumCapacity)
            // The only place that currently calls expects reserve the same capacity for both stored properties.
            // This is because symbols are 
            referencesBySymbolID.reserveCapacity(minimumCapacity)
        }
        
        /// Returns a list of all the references in the cache.
        var allReferences: some Collection<ResolvedTopicReference> {
            return valuesByReference.keys
        }
        
        /// Returns a list of all the references in the cache.
        var symbolReferences: some Collection<ResolvedTopicReference> {
            return referencesBySymbolID.values
        }
    }
}

// Support iterating over the cached values, checking the number of cached values, and other collection operations.
extension DocumentationContext.ContentCache: Collection {
    typealias Wrapped = [ResolvedTopicReference: Value]
    typealias Index = Wrapped.Index
    typealias Element = Wrapped.Element
    
    func makeIterator() -> Wrapped.Iterator {
        valuesByReference.makeIterator()
    }
    
    var startIndex: Wrapped.Index {
        valuesByReference.startIndex
    }
    
    var endIndex: Wrapped.Index {
        valuesByReference.endIndex
    }
    
    func index(after i: Wrapped.Index) -> Wrapped.Index {
        valuesByReference.index(after: i)
    }
    
    subscript(position: Wrapped.Index) -> Wrapped.Element {
        _read { yield valuesByReference[position] }
    }
}