Last active
August 29, 2015 14:16
-
-
Save JadenGeller/7377b4422a71d6b63b96 to your computer and use it in GitHub Desktop.
Swift Long Jump Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// We will show how long jumps can be used within Swift | |
// Create jump and set it's position | |
let start = Jump() | |
setjmp(start.line) // Sets start's line to the current line | |
println("HI") // -> "Hi" -> "Hi" -> "Hi" -> ... (prints forever) | |
longjmp(start.line, 0) // Jumps back to start's line, e.g. setjmp(start.line) | |
// We have created an infinite loop using jumps! | |
// Now let's do something more useful: We will create a while loop! | |
func myWhile(test: () -> Bool, loop:() -> ()){ | |
let start = Jump() | |
setjmp(start.line) | |
if (test()){ | |
loop() | |
longjmp(start.line, 0) | |
} | |
} | |
// Now we will use our loop! | |
var x = 0 | |
myWhile({ x < 3 }){ | |
println("Hello world") // -> "Hello world" | |
x++ // "Hello world" | |
} // "Hello world" | |
// Let's look at a more advanced example | |
// It turns our that setjmp actually returns whatever value is passed into longjmp | |
// (unless the value 0 is passed in in which case setjmp returns 1) | |
// (and setjmp returns 0 the first time it is called) | |
// Note that setjmp and longjmp use Int32, so cast accordingly | |
func doNTimes(n: Int, loop:() -> ()){ | |
let start = Jump() | |
let count = Int(setjmp(start.line)) | |
if (count < n){ | |
loop() | |
longjmp(start.line, count + 1) | |
} | |
} | |
doNTimes(3){ | |
println("Whoa") // -> "Whoa" | |
} // "Whoa" | |
// "Whoa" | |
// One more thing: Let's modify myWhile to support continue and break calls! | |
func myWhile(test: () -> Bool, loop:(myContinue: () -> (), myBreak: () -> ()) -> ()) { | |
let start = Jump() | |
let stop = Int(setjmp(start.line)) | |
if (stop != -1 && test()){ | |
loop({ longjmp(start.line, 0) }, { longjmp(start.line, -1) }) | |
longjmp(start.line, 0) | |
} | |
} | |
// Tahdah!! | |
var x = 0 | |
myWhile({ true }) { myContinue, myBreak in | |
x++ | |
println("Considering \(x)") | |
if x % 2 == 0 { myContinue() } // skip even numbers | |
println("Using \(x)") | |
if x > 9 { myBreak() } // print numbers less than or equal to 11 | |
} | |
// Now for the actual implementation | |
// Turns out that I didn't really do much to make this possible | |
// C already has this feature built in, so naturally Swift does too | |
// I just wrapped up the malloc and free calls so you don't have to worry | |
class Jump { | |
typealias JumpType = UnsafeMutablePointer<Int32> | |
private let jumpSize = UInt(sizeof(jmp_buf)) | |
let line: JumpType | |
init() { | |
line = JumpType(malloc(jumpSize)) | |
} | |
deinit { | |
free(line) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment