@@ -20,27 +20,27 @@ public class BumpPtrAllocator {
20
20
static private var SLAB_ALIGNMENT : Int = 8
21
21
22
22
private var slabs : [ Slab ]
23
- /// Points to the next unused address in `slabs.last`.
24
- private var currentPtr : UnsafeMutableRawPointer ?
25
- /// Points to the end address of `slabs.last`. If `slabs` is not empty, this
26
- /// is equivalent to `slabs.last!.baseAddress! + slabs.last!.count`
27
- private var endPtr : UnsafeMutableRawPointer ?
23
+ /// Pair of pointers in the current slab.
24
+ /// - pointer: Points to the next unused address in `slabs.last`.
25
+ /// - end: Points to the end address of `slabs.last`. This is equivalent to
26
+ /// `slabs.last!.baseAddress! + slabs.last!.count`
27
+ /// 'nil' if `slabs` is empty.
28
+ private var current : ( pointer: UnsafeMutableRawPointer ,
29
+ end: UnsafeMutableRawPointer ) ?
28
30
private var customSizeSlabs : [ Slab ]
29
31
private var _totalBytesAllocated : Int
30
32
31
33
public init ( ) {
32
34
slabs = [ ]
33
- currentPtr = nil
34
- endPtr = nil
35
+ current = nil
35
36
customSizeSlabs = [ ]
36
37
_totalBytesAllocated = 0
37
38
}
38
39
39
40
deinit {
40
41
/// Deallocate all memory.
41
42
_totalBytesAllocated = 0
42
- currentPtr = nil
43
- endPtr = nil
43
+ current = nil
44
44
while let slab = slabs. popLast ( ) {
45
45
slab. deallocate ( )
46
46
}
@@ -59,9 +59,28 @@ public class BumpPtrAllocator {
59
59
let newSlabSize = Self . slabSize ( at: slabs. count)
60
60
let newSlab = Slab . allocate (
61
61
byteCount: newSlabSize, alignment: Self . SLAB_ALIGNMENT)
62
+ let pointer = newSlab. baseAddress!
63
+ current = ( pointer, pointer. advanced ( by: newSlabSize) )
62
64
slabs. append ( newSlab)
63
- currentPtr = newSlab. baseAddress!
64
- endPtr = currentPtr!. advanced ( by: newSlabSize)
65
+ }
66
+
67
+ /// Allocate 'byteCount' of memory from the current slab if available.
68
+ private func allocateFromCurrentSlab(
69
+ _ byteCount: Int ,
70
+ _ alignment: Int
71
+ ) -> UnsafeMutableRawBufferPointer ? {
72
+ guard let current = self . current else {
73
+ return nil
74
+ }
75
+
76
+ let aligned = current. pointer. alignedUp ( toMultipleOf: alignment)
77
+ guard byteCount <= aligned. distance ( to: current. end) else {
78
+ return nil
79
+ }
80
+
81
+ // Bump the pointer, and return the allocated buffer.
82
+ self . current = ( aligned + byteCount, current. end)
83
+ return . init( start: aligned, count: byteCount)
65
84
}
66
85
67
86
/// Allocate 'byteCount' of memory.
@@ -70,7 +89,7 @@ public class BumpPtrAllocator {
70
89
/// Clients should never call `deallocate()` on the returned buffer.
71
90
public func allocate( byteCount: Int , alignment: Int ) -> UnsafeMutableRawBufferPointer {
72
91
73
- precondition ( alignment <= Self . SLAB_ALIGNMENT)
92
+ assert ( alignment <= Self . SLAB_ALIGNMENT)
74
93
guard byteCount > 0 else {
75
94
return . init( start: nil , count: 0 )
76
95
}
@@ -79,12 +98,8 @@ public class BumpPtrAllocator {
79
98
_totalBytesAllocated += byteCount
80
99
81
100
// Check if the current slab has enough space.
82
- if !slabs. isEmpty {
83
- let aligned = currentPtr!. alignedUp ( toMultipleOf: alignment)
84
- if aligned + byteCount <= endPtr! {
85
- currentPtr = aligned + byteCount
86
- return . init( start: aligned, count: byteCount)
87
- }
101
+ if let allocated = allocateFromCurrentSlab ( byteCount, alignment) {
102
+ return allocated
88
103
}
89
104
90
105
// If the size is too big, allocate a dedicated slab for it.
@@ -97,10 +112,10 @@ public class BumpPtrAllocator {
97
112
98
113
// Otherwise, start a new slab and try again.
99
114
startNewSlab ( )
100
- let aligned = currentPtr! . alignedUp ( toMultipleOf : alignment)
101
- assert ( aligned + byteCount <= endPtr! , " Unable to allocate memory! " )
102
- currentPtr = aligned + byteCount
103
- return . init ( start : aligned , count : byteCount )
115
+ if let allocated = allocateFromCurrentSlab ( byteCount , alignment) {
116
+ return allocated
117
+ }
118
+ fatalError ( " Unable to allocate memory! " )
104
119
}
105
120
106
121
/// Allocate a chunk of bound memory of `MemoryLayout<T>.stride * count'.
0 commit comments