Skip to content

Instantly share code, notes, and snippets.

@VojtaStavik
Created March 16, 2016 16:22
Show Gist options
  • Save VojtaStavik/b3073c9b5f186016e639 to your computer and use it in GitHub Desktop.
Save VojtaStavik/b3073c9b5f186016e639 to your computer and use it in GitHub Desktop.
import Foundation
class PointerBox<Element> {
var pointer: UnsafeMutablePointer<Element>
let count: Int
init(pointer: UnsafeMutablePointer<Element>, count: Int) {
self.pointer = pointer
self.count = count
}
deinit {
pointer.destroy(count)
pointer.dealloc(count)
pointer = nil
}
}
struct MyArray<Element> {
private var buffer: PointerBox<Element>
private(set) var count = 0
init() {
buffer = PointerBox(pointer: UnsafeMutablePointer<Element>.alloc(count), count: count)
}
func elementAtIndex(index: Int) -> Element {
precondition(index < count)
return buffer.pointer[index]
}
}
extension MyArray: ArrayLiteralConvertible {
init(arrayLiteral elements: Element...) {
count = elements.count
buffer = PointerBox(pointer: UnsafeMutablePointer<Element>.alloc(count), count: count)
buffer.pointer.initializeFrom(elements)
}
}
extension MyArray: CollectionType {
typealias Generator = IndexingGenerator<MyArray>
func generate() -> Generator {
return Generator(self)
}
typealias Index = Int
var startIndex: Index { return 0 }
var endIndex: Index { return count }
subscript(position: Index) -> Element {
get { return elementAtIndex(position) }
}
}
extension MyArray: RangeReplaceableCollectionType {
mutating func replaceRange<C : CollectionType where C.Generator.Element == Generator.Element>(subRange: Range<MyArray.Index>, with newElements: C) {
let rangeLength = subRange.startIndex.distanceTo(subRange.endIndex)
let countDelta = newElements.count.toIntMax() - rangeLength
let newNumberOfElements = count + Int(countDelta)
// Create new buffer
let newBuffer = UnsafeMutablePointer<Element>.alloc(newNumberOfElements)
let newElementsStartIndex = Int(subRange.startIndex.toIntMax())
let newElementsEndIndex = Int(newElementsStartIndex + newElements.count.toIntMax())
// We use generators to iterate through original and new elementes
var newElementsIndicesGenerator = newElements.indices.generate()
var originalIndicesGenerator = self.indices.filter{ subRange.contains($0) == false }.generate()
for i in (0..<newNumberOfElements) {
if newElementsStartIndex <= i && i < newElementsEndIndex {
let e = newElements[newElementsIndicesGenerator.next()!]
newBuffer.advancedBy(i).initialize(e)
} else {
let e = self[originalIndicesGenerator.next()!]
newBuffer.advancedBy(i).initialize(e)
}
}
count = 0
self.buffer = PointerBox(pointer: newBuffer, count: newNumberOfElements)
self.count = newNumberOfElements
}
}
extension MyArray: CustomStringConvertible {
var description: String {
return "[" + self.map{"\"\($0)\""}.joinWithSeparator(", ") + "]"
}
}
var a: MyArray = ["a", "b", "c", "d"]
a.replaceRange(Range<Int>(start: 2, end: 3), with: ["1", "2", "3", "4"])
a.append("new element 1")
a.insert("🙀", atIndex: 3)
a.removeFirst()
let aa = a
a.removeFirst(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment