Skip to content

Commit c3d03b9

Browse files
committed
Finished implementation explination
1 parent 1d16285 commit c3d03b9

File tree

2 files changed

+86
-26
lines changed

2 files changed

+86
-26
lines changed

Rootish Array Stack/README.md

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public struct RootishArrayStack<T> {
9696
return internalCount
9797
}
9898

99+
...
100+
101+
}
99102

100103
```
101104
The elements are of generic type `T`, so data of any kind can be stored in the list. `blocks` will be a resizable array to hold fixed sized arrays that take type `T?`.
@@ -110,7 +113,7 @@ var capacity: Int {
110113
}
111114
```
112115

113-
Next lets build what we need to get/set elements:
116+
Next lets look at we would `get` and `set` elements:
114117
```swift
115118
fileprivate func toBlock(index: Int) -> Int {
116119
let block = Int(ceil((-3.0 + sqrt(9.0 + 8.0 * Double(index))) / 2))
@@ -130,4 +133,66 @@ public subscript(index: Int) -> T {
130133
}
131134
}
132135
```
133-
`toBlock` is really just wrapping the `block` equation derived earlier. `superscript` lets us have `get/set` access to the structure with the familiar `[index]` syntax.
136+
`toBlock(index:)` is really just wrapping the `block` equation derived earlier to return the block that an index maps to. `superscript` lets us have `get` and `set` access to the structure with the familiar `[index:]` syntax. For both `get` and `set` in superscript we use the same logic:
137+
1. determine the block that the index points to
138+
2. determine the inner block index
139+
3. `get`/`set` the value
140+
141+
Next lets look at how we would `growIfNeeded()` and `shrinkIfNeeded()` the structure.
142+
```swift
143+
fileprivate mutating func growIfNeeded() {
144+
if capacity - blocks.count < count + 1 {
145+
let newArray = [T?](repeating: nil, count: blocks.count + 1)
146+
blocks.append(newArray)
147+
}
148+
}
149+
150+
fileprivate mutating func shrinkIfNeeded() {
151+
if capacity + blocks.count >= count {
152+
var numberOfBlocks = blocks.count
153+
while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count {
154+
blocks.remove(at: blocks.count - 1)
155+
numberOfBlocks -= 1
156+
}
157+
}
158+
}
159+
```
160+
If our data set grows or shrinks in size, we want our data structure to accommodate the change.
161+
Just like a Swift array when a capacity threshold is met we will `grow` or `shrink` the size of our structure. For the Rootish Array Stack we want to `grow` if the second last block is full on an `insert` operation, and `shrink` if the two last blocks are empty.
162+
163+
Now to the more familiar Swift array behaviour.
164+
```swift
165+
public mutating func insert(element: T, atIndex index: Int) {
166+
growIfNeeded()
167+
internalCount += 1
168+
var i = count - 1
169+
while i > index {
170+
self[i] = self[i - 1]
171+
i -= 1
172+
}
173+
self[index] = element
174+
}
175+
176+
public mutating func append(element: T) {
177+
insert(element: element, atIndex: count)
178+
}
179+
180+
public mutating func remove(atIndex index: Int) -> T {
181+
let element = self[index]
182+
for i in index..<count - 1 {
183+
self[i] = self[i + 1]
184+
}
185+
internalCount -= 1
186+
makeNil(atIndex: count)
187+
shrinkIfNeeded()
188+
return element
189+
}
190+
191+
fileprivate mutating func makeNil(atIndex index: Int) {
192+
let block = toBlock(index: index)
193+
let blockIndex = index - block * (block + 1) / 2
194+
blocks[block][blockIndex] = nil
195+
}
196+
```
197+
To `insert(element:, atIndex:)` we move all elements after the `index` to the right by 1. After space has been made for the element we set the value using the `subscript` convenience. `append(element:)` is just a convenience method to add to the end. To `remove(atIndex:)` we move all the elements after the `index` to the left by 1. After the removed value is covered by it's proceeding value, we set the last value in the structure to `nil`. `makeNil(atIndex:)` uses the same logic as our `subscript` method but is used to set the root optional at a particular index to `nil` (because setting it's wrapped value to `nil` is something only the user of the data structure should do).
198+
> Setting a optionals value to `nil` is different than setting it's wrapped value to `nil`. An optionals wrapped value is an embedded type within the optional reference. This means that a `nil` wrapped value is actually `.some(.none)` wheres setting the root reference to `nil` is `.none`. To better understand Swift optionals I recommend checking out @SebastianBoldt's article [Swift! Optionals?](https://medium.com/ios-os-x-development/swift-optionals-78dafaa53f3#.rvjobhuzs).

Rootish Array Stack/RootishArrayStack.swift

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ public struct RootishArrayStack<T> {
2626
return block
2727
}
2828

29+
fileprivate mutating func growIfNeeded() {
30+
if capacity - blocks.count < count + 1 {
31+
let newArray = [T?](repeating: nil, count: blocks.count + 1)
32+
blocks.append(newArray)
33+
}
34+
}
35+
36+
fileprivate mutating func shrinkIfNeeded() {
37+
if capacity + blocks.count >= count {
38+
var numberOfBlocks = blocks.count
39+
while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count {
40+
blocks.remove(at: blocks.count - 1)
41+
numberOfBlocks -= 1
42+
}
43+
}
44+
}
45+
2946
public subscript(index: Int) -> T {
3047
get {
3148
let block = toBlock(index: index)
@@ -39,23 +56,8 @@ public struct RootishArrayStack<T> {
3956
}
4057
}
4158

42-
fileprivate mutating func grow() {
43-
let newArray = [T?](repeating: nil, count: blocks.count + 1)
44-
blocks.append(newArray)
45-
}
46-
47-
fileprivate mutating func shrink() {
48-
var numberOfBlocks = blocks.count
49-
while numberOfBlocks > 0 && (numberOfBlocks - 2) * (numberOfBlocks - 1) / 2 >= count {
50-
blocks.remove(at: blocks.count - 1)
51-
numberOfBlocks -= 1
52-
}
53-
}
54-
5559
public mutating func insert(element: T, atIndex index: Int) {
56-
if capacity - blocks.count < count + 1 {
57-
grow()
58-
}
60+
growIfNeeded()
5961
internalCount += 1
6062
var i = count - 1
6163
while i > index {
@@ -82,9 +84,7 @@ public struct RootishArrayStack<T> {
8284
}
8385
internalCount -= 1
8486
makeNil(atIndex: count)
85-
if capacity + blocks.count >= count {
86-
shrink()
87-
}
87+
shrinkIfNeeded()
8888
return element
8989
}
9090

@@ -113,8 +113,3 @@ extension RootishArrayStack: CustomStringConvertible {
113113
return s + "]"
114114
}
115115
}
116-
117-
var list = RootishArrayStack<Int>()
118-
for i in 0...10 {
119-
list.append(element: i)
120-
}

0 commit comments

Comments
 (0)