117 lines
4.0 KiB
C
Raw Permalink Normal View History

//
// EXTScope.h
// extobjc
//
// Created by Justin Spahr-Summers on 2011-05-04.
// Copyright (C) 2012 Justin Spahr-Summers.
// Released under the MIT license.
//
#import <WMF/metamacros.h>
/**
* \@onExit defines some code to be executed when the current scope exits. The
* code must be enclosed in braces and terminated with a semicolon, and will be
* executed regardless of how the scope is exited, including from exceptions,
* \c goto, \c return, \c break, and \c continue.
*
* Provided code will go into a block to be executed later. Keep this in mind as
* it pertains to memory management, restrictions on assignment, etc. Because
* the code is used within a block, \c return is a legal (though perhaps
* confusing) way to exit the cleanup block early.
*
* Multiple \@onExit statements in the same scope are executed in reverse
* lexical order. This helps when pairing resource acquisition with \@onExit
* statements, as it guarantees teardown in the opposite order of acquisition.
*
* @note This statement cannot be used within scopes defined without braces
* (like a one line \c if). In practice, this is not an issue, since \@onExit is
* a useless construct in such a case anyways.
*/
#define onExit \
ext_keywordify \
__strong ext_cleanupBlock_t metamacro_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^
/**
* Creates \c __weak shadow variables for each of the variables provided as
* arguments, which can later be made strong again with #strongify.
*
* This is typically used to weakly reference variables in a block, but then
* ensure that the variables stay alive during the actual execution of the block
* (if they were live upon entry).
*
* See #strongify for an example of usage.
*/
#define weakify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)
/**
* Like #weakify, but uses \c __unsafe_unretained instead, for targets or
* classes that do not support weak references.
*/
#define unsafeify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __unsafe_unretained, __VA_ARGS__)
/**
* Strongly references each of the variables provided as arguments, which must
* have previously been passed to #weakify.
*
* The strong references created will shadow the original variable names, such
* that the original names can be used without issue (and a significantly
* reduced risk of retain cycles) in the current scope.
*
* @code
id foo = [[NSObject alloc] init];
id bar = [[NSObject alloc] init];
@weakify(foo, bar);
// this block will not keep 'foo' or 'bar' alive
BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){
// but now, upon entry, 'foo' and 'bar' will stay alive until the block has
// finished executing
@strongify(foo, bar);
return [foo isEqual:obj] || [bar isEqual:obj];
};
* @endcode
*/
#define strongify(...) \
ext_keywordify \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(ext_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")
/*** implementation details follow ***/
typedef void (^ext_cleanupBlock_t)(void);
void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block);
#define ext_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
#define ext_strongify_(INDEX, VAR) \
__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
// Details about the choice of backing keyword:
//
// The use of @try/@catch/@finally can cause the compiler to suppress
// return-type warnings.
// The use of @autoreleasepool {} is not optimized away by the compiler,
// resulting in superfluous creation of autorelease pools.
//
// Since neither option is perfect, and with no other alternatives, the
// compromise is to use @autorelease in DEBUG builds to maintain compiler
// analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary
// autorelease pools.
#if DEBUG
#define ext_keywordify autoreleasepool {}
#else
#define ext_keywordify try {} @catch (...) {}
#endif