@@ -42,3 +42,85 @@ struct _DictionaryBuilder<Key: Hashable, Value> {
42
42
return Dictionary ( _native: _target)
43
43
}
44
44
}
45
+
46
+ extension Dictionary {
47
+ /// Creates a new dictionary with the specified capacity, then calls the given
48
+ /// closure to initialize its contents.
49
+ ///
50
+ /// Foundation uses this initializer to bridge the contents of an NSDictionary
51
+ /// instance without allocating a pair of intermediary buffers. Pass the
52
+ /// required capacity and a closure that can intialize the dictionary's
53
+ /// elements. The closure must return `c`, the number of initialized elements
54
+ /// in both buffers, such that the elements in the range `0..<c` are
55
+ /// initialized and the elements in the range `c..<capacity` are
56
+ /// uninitialized. The resulting dictionary has a `count` equal to `c`.
57
+ ///
58
+ /// The closure must not add any duplicate keys to the keys buffer. The
59
+ /// buffers passed to the closure are only valid for the duration of the call.
60
+ /// After the closure returns, this initializer moves all initialized elements
61
+ /// into their correct buckets.
62
+ ///
63
+ /// - Parameters:
64
+ /// - capacity: The capacity of the new dictionary.
65
+ /// - body: A closure that can initialize the dictionary's elements. This
66
+ /// closure must return the count of the initialized elements, starting at
67
+ /// the beginning of the buffer.
68
+ @inlinable
69
+ public // SPI(Foundation)
70
+ init (
71
+ _unsafeUninitializedCapacity capacity: Int ,
72
+ initializingWith initializer: (
73
+ _ keys: UnsafeMutableBufferPointer < Key > ,
74
+ _ values: UnsafeMutableBufferPointer < Value > ,
75
+ _ initializedCount: inout Int
76
+ ) -> Void
77
+ ) {
78
+ let native = _NativeDictionary < Key , Value > ( capacity: capacity)
79
+ let keys = UnsafeMutableBufferPointer < Key > (
80
+ start: native. _keys,
81
+ count: capacity)
82
+ let values = UnsafeMutableBufferPointer < Value > (
83
+ start: native. _values,
84
+ count: capacity)
85
+ var count = 0
86
+ initializer ( keys, values, & count)
87
+ _precondition ( count >= 0 && count <= capacity)
88
+
89
+ // Hash elements into the correct buckets.
90
+ var bucket = _HashTable. Bucket ( offset: 0 )
91
+ while bucket. offset < count {
92
+ if native. hashTable. _isOccupied ( bucket) {
93
+ // We've moved an element here in a previous iteration.
94
+ bucket. offset += 1
95
+ continue
96
+ }
97
+ let hashValue = native. hashValue ( for: native. _keys [ bucket. offset] )
98
+ let target : _HashTable . Bucket
99
+ if _isDebugAssertConfiguration ( ) {
100
+ let ( b, found) = native. find (
101
+ native. _keys [ bucket. offset] ,
102
+ hashValue: hashValue)
103
+ guard !found else {
104
+ _preconditionFailure ( " Duplicate keys found " )
105
+ }
106
+ native. hashTable. insert ( b)
107
+ target = b
108
+ } else {
109
+ target = native. hashTable. insertNew ( hashValue: hashValue)
110
+ }
111
+ if target < bucket || target. offset >= count {
112
+ // Target bucket is uninitialized
113
+ native. moveEntry ( from: bucket, to: target)
114
+ bucket. offset += 1
115
+ } else if target == bucket {
116
+ // Already in place
117
+ bucket. offset += 1
118
+ } else {
119
+ // Swap into place, then try again with the swapped-in value.
120
+ native. swapEntry ( target, with: bucket)
121
+ }
122
+ }
123
+ native. _storage. _count = count
124
+ self = Dictionary ( _native: native)
125
+ }
126
+ }
0 commit comments