1 #pragma once 2 3 #include <functional> 4 5 /** Type that gives an lvalue a dynamically-scoped temporary value. An 6 * unwind_var wraps a variable or other writable lvalue, assigns it a 7 * temporary value, and restores the original (or a specified) value when 8 * the unwind_var goes out of scope or is otherwise destroyed. 9 */ 10 template <typename T> 11 class unwind_var 12 { 13 public: 14 /** Wrap the lvalue val_ and on unwinding restore its original value. */ unwind_var(T & val_)15 unwind_var(T &val_) : val(val_), oldval(val_) { } 16 17 /** Wrap the lvalue val_, assign it the temporary value newval, and 18 * on unwinding restore its original value. 19 */ unwind_var(T & val_,T newval)20 unwind_var(T &val_, T newval) : val(val_), oldval(val_) 21 { 22 val = newval; 23 } 24 25 /** Wrap the lvalue val_, assign it the temporary value newval, and 26 * on unwinding assign it the value reset_to. 27 */ unwind_var(T & val_,T newval,T reset_to)28 unwind_var(T &val_, T newval, T reset_to) : val(val_), oldval(reset_to) 29 { 30 val = newval; 31 } 32 ~unwind_var()33 ~unwind_var() 34 { 35 val = oldval; 36 } 37 38 /** Get the current (temporary) value of the wrapped lvalue. */ value()39 T value() const 40 { 41 return val; 42 } 43 44 /** Get the value that will be used to restore the wrapped lvalue. */ original_value()45 T original_value() const 46 { 47 return oldval; 48 } 49 50 private: 51 T &val; 52 T oldval; 53 }; 54 55 typedef unwind_var<bool> unwind_bool; 56 57 /** Type to call a function when an instance goes out of scope or is 58 * otherwise destroyed. 59 */ 60 class unwinder 61 { 62 public: 63 /** Construct an unwinder that calls cleanup_fn when destroyed. */ 64 // We templatise the parameter, rather than taking a function<>, so that 65 // we can write "unwinder foo = [](){};" without running into the 66 // "only one user-defined conversion at a time" rule. 67 template<class Fn> unwinder(Fn cleanup_fn)68 unwinder(Fn cleanup_fn) : cleaner(cleanup_fn) { } 69 ~unwinder()70 ~unwinder() 71 { 72 if (cleaner) 73 cleaner(); 74 } 75 76 /** Cancel this unwinder, so that it calls nothing when destroyed. */ cancel()77 void cancel() 78 { 79 cleaner = nullptr; 80 } 81 private: 82 function<void ()> cleaner; 83 }; 84 85 // Preprocessor tricks, ugh. 86 #define CONCAT_IMPL(x, y) x##y 87 #define CONCAT_TOK(x, y) CONCAT_IMPL(x, y) 88 89 /** Set up a block of code to run when the current scope is exited. 90 * 91 * Usage: ON_UNWIND { block of code here }; 92 * 93 * Defines a variable, with a generated name, to hold the unwinder. 94 */ 95 #define ON_UNWIND unwinder CONCAT_TOK(_gensym_uw_, __LINE__) = [&] () -> void 96