Last active
August 29, 2015 14:16
-
-
Save JadenGeller/c40d465fe4a1f653a1f1 to your computer and use it in GitHub Desktop.
Swift Restart Skip Block
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
// Let's start with an example | |
var c = 0 | |
// Inside a jump block, calling the restart function starts over | |
// and calling the skip function exists the block | |
jump { restart, skip in | |
for i in 1...4 { | |
println("c: \(c); i: \(i)") | |
if c == 4 { skip() } | |
else if i == 3 { c++; restart() } | |
} | |
} | |
// We will use the jump function to implement a while loop! | |
func myWhile(test: () -> Bool, loop: () -> ()) { | |
jump { restart, skip in | |
if test() { | |
loop() | |
restart() | |
} | |
} | |
} | |
var x = 0 | |
myWhile({ x < 3 }){ | |
println(x++) // -> 0 --> 1 --> 2 | |
} | |
// Note that this is equivalent to having a start: goto before our block | |
// and a skip: goto after our block in a lanaguage that supports gotos | |
// Note that this is also equivalent to the following | |
// Also note that this simpler alternative cannot be implemented with closures | |
// because continue and break cannot be used in closures even if called by a loop | |
var repeat = true | |
while repeat { | |
// Insert code goes here | |
// restart() --> continue | |
// skip() --> repeat = false; break | |
repeat = false | |
} | |
// Implementation, it's pretty cool | |
// We use C's setjmp and longjmp | |
typealias JumpType = UnsafeMutablePointer<Int32> | |
let jumpSize = UInt(sizeof(jmp_buf)) | |
func jump(f: (() -> (), () -> ()) -> ()) { | |
// Malloc | |
let skip = JumpType(malloc(jumpSize)) | |
let restart = JumpType(malloc(jumpSize)) | |
// Declare restart jump | |
let didRestart = setjmp(restart) | |
// Wait for setup, and then call | |
if (didRestart != 0) { | |
f({ longjmp(restart, Int32(-1)) }, { longjmp(skip, Int32(-1)) }) | |
} | |
let didSkip = setjmp(skip) | |
// If we haven't yet run the function, skip back to the start | |
if (didSkip == 0) { | |
longjmp(restart, Int32(-1)) | |
} | |
// Avoid memory leakage | |
free(skip) | |
free(restart) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment