// // Block.h // HigherOrderMessaging // // Created by Ofri Wolfus on 14/12/06. // Copyright 2006 Ofri Wolfus. All rights reserved. // #import #include typedef struct dp_block_data *Block; // Allocates and returns a new block structure. // You should never use this function directly. DP_EXTERN Block block_init(Block b); //DP_EXTERN Block block_create(); // Frees the memory used by the passed block. // Call this function when you're done working with your block (which // will usually be inside the function that takes the block). //DP_EXTERN void block_free(Block b); // Executes the code contained by the block, and reinvokes the calling function // with the same block. DP_EXTERN_INLINE void block_process(Block b); // Sets/gets private info from a given block. // You can use this info to hold data for your iteration methods/functions. // Keys must be ObjC objects or CFType instances which will be copied and released // when the block is freed. Values can be any pointer type // (which will not be retained/released). DP_EXTERN_INLINE void block_set_value_for_key(Block b, void *val, id key); DP_EXTERN_INLINE void * block_get_value_for_key(Block b, id key); // Returns whether a given block is initialized. // block_process() automatically marks the block as initialized the first // time it is being called with a given block. DP_EXTERN_INLINE BOOL block_is_initialized(Block b); DP_EXTERN_INLINE size_t block_get_size(); /*! * @abstract Creates and returns a block sturcture. * @discussion The use of this macro must be nested inside a function/method call * as one of the arguments. Creating blocks outside of this context will result in * an undefined behaviour. * A block definition goes like this: DPBlock(int i = 3; id o = nil; begin: NSLog(@"%d", i);) * Every block definition begins with variable definition(s) followed by the keyword "begin:", * and then the content of the block. The variable definition(s) may be omitted, in which case * the definition will look like this: DPBlock(begin: ...). * Variables defined in the content section of a block (that is, after the "begin:" keyword) * will not preserve their values between invocations of the block. * Every block defines a hidden variable of type id named "each". * Blocks that are passed to iteration methods/functions modify the content of this variable * during the iteration, before the block's content is executed, so you can use blocks perform * actions on objects of collections like this: [someArray foreach:DPBlock(begin: NSLog(@"%@", each)]; * Note: The last statement of the block's content may omit the semicolon at the end. */ #define Block(statements...) \ ({ \ __label__ __block_begin; \ Block __block = block_init(alloca(block_get_size())); \ __block_begin: \ if (setjmp(*((jmp_buf*)__block))) { \ id each = (id)block_get_value_for_key(__block, @"each"); \ statements; \ goto __block_begin; \ } \ __block; \ })