Skip to content

Instantly share code, notes, and snippets.

@JadenGeller
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JadenGeller/7377b4422a71d6b63b96 to your computer and use it in GitHub Desktop.
Save JadenGeller/7377b4422a71d6b63b96 to your computer and use it in GitHub Desktop.
Swift Long Jump Wrapper
// 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