├── EXTScope ├── EXTScope.m ├── EXTScope.h └── metamacros.h ├── UIView+Tools ├── UILabel+Tools.h ├── UIView+Tools.h ├── UILabel+Tools.m ├── UIView+AnimationExtensions.h ├── UIView+AnimationExtensions.m └── UIView+Tools.m ├── HudTools.h ├── NSString+Tools ├── NSString+Tools.h └── NSString+Tools.m ├── Swift ├── StructCoding.swift └── UIView-Extension.swift ├── MangoLog ├── MangoLog.h └── MangoLog.m ├── Macro └── MangoMacro.h ├── NSAttributedString+Attributes ├── NSAttributedString+Attributes.h └── NSAttributedString+Attributes.m ├── HudTools.m ├── README.md └── NSDate+Utilities ├── NSDate+Utilities.h └── NSDate+Utilities.m /EXTScope/EXTScope.m: -------------------------------------------------------------------------------- 1 | // 2 | // EXTScope.m 3 | // extobjc 4 | // 5 | // Created by Justin Spahr-Summers on 2011-05-04. 6 | // Copyright (C) 2012 Justin Spahr-Summers. 7 | // Released under the MIT license. 8 | // 9 | 10 | #import "EXTScope.h" 11 | 12 | void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block) { 13 | (*block)(); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /UIView+Tools/UILabel+Tools.h: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel+Tools.h 3 | // 4 | // Created by Mango on 15/12/4. 5 | // Copyright © 2015年 Mango. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface UILabel (Tools) 11 | 12 | - (void)setText:(NSString *)text highlightKeyWord:(NSArray *)keywords highlightColor:(UIColor*)color; 13 | - (void)adjustFontSizeToFitBounds; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /HudTools.h: -------------------------------------------------------------------------------- 1 | // 2 | // Tools.h 3 | // shike 4 | // 5 | // Copyright (c) 2014年 shixun. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | // TODO: 这个类可以多加几个分类 以免方法太多. 11 | 12 | @interface HudTools : NSObject 13 | 14 | + (void)dismiss; 15 | + (void)showStatusWithString:(NSString *)string; 16 | + (void)showErrorWithString:(NSString *)string; 17 | + (void)showSuccessWithString:(NSString *)string; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- / NSString+Tools/NSString+Tools.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Tools.h 3 | // Trans 4 | // 5 | // Created by Mango on 15/2/2. 6 | // Copyright (c) 2015年 Mango. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Tools) 12 | 13 | - (BOOL)isMobileNumber:(NSString *)mobileNum; 14 | 15 | //只检查车牌号 (不包括缩写与英文代号:例如:京A) 16 | - (BOOL)isCarNumber; 17 | 18 | //构造URL,如果没有http前缀,则添加 19 | +(NSURL *)HTTPURLFromString:(NSString *)string; 20 | 21 | //返回构造好的时间字符串 60s-> 00:00:60 22 | + (NSString *)timeStringFromSeconds:(int)totalSeconds; 23 | @end 24 | -------------------------------------------------------------------------------- /Swift/StructCoding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StructCoding.swift 3 | // Celluloid 4 | // 5 | // Created by Mango on 16/3/16. 6 | // Copyright © 2016年 Mango. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol StructCoding { 12 | associatedtype structType 13 | 14 | mutating func encode() -> NSData 15 | 16 | static func decode(data: NSData) -> Self 17 | } 18 | 19 | public extension StructCoding { 20 | 21 | public mutating func encode() -> NSData { 22 | return withUnsafePointer(&self) { p in 23 | NSData(bytes: p, length: sizeofValue(self)) 24 | } 25 | } 26 | 27 | public static func decode(data: NSData) -> structType { 28 | let pointer = UnsafeMutablePointer.alloc(sizeof(structType)) 29 | data.getBytes(pointer, length: sizeof(structType)) 30 | return pointer.move() 31 | } 32 | } -------------------------------------------------------------------------------- /MangoLog/MangoLog.h: -------------------------------------------------------------------------------- 1 | // 2 | // MangoLog.h 3 | // 4 | // Created by Mango on 15/7/24. 5 | // 6 | 7 | #import 8 | 9 | @class MangoLog; 10 | 11 | #define MGLog(format, ...) \ 12 | do \ 13 | { \ 14 | NSString *position = [NSString stringWithFormat:@"%s [Line %d]\n", \ 15 | __PRETTY_FUNCTION__,__LINE__]; \ 16 | NSString *userDefineString = [NSString stringWithFormat:format,##__VA_ARGS__]; \ 17 | NSString *logString = [NSString stringWithFormat:@"%@%@",position,userDefineString]; \ 18 | NSLog(@"%@",logString); \ 19 | [MangoLog writeLogString:logString];\ 20 | } while (0);\ 21 | 22 | #define MGLogWithoutWriteFile(format, ...) \ 23 | do \ 24 | { \ 25 | NSString *position = [NSString stringWithFormat:@"%s [Line %d]\n", \ 26 | __PRETTY_FUNCTION__,__LINE__]; \ 27 | NSString *userDefineString = [NSString stringWithFormat:format,##__VA_ARGS__]; \ 28 | NSString *logString = [NSString stringWithFormat:@"%@%@",position,userDefineString]; \ 29 | NSLog(@"%@",logString); \ 30 | } while (0);\ 31 | 32 | @interface MangoLog : NSObject 33 | 34 | + (void)writeLogString:(NSString*)logString; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Macro/MangoMacro.h: -------------------------------------------------------------------------------- 1 | // 2 | // MangoMacro.h 3 | // 4 | // Created by Mango on 16/2/1. 5 | // Copyright © 2016年 Mango. All rights reserved. 6 | // 7 | 8 | #ifndef MangoMacro_h 9 | #define MangoMacro_h 10 | 11 | #define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 12 | #define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 13 | #define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0) 14 | 15 | #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) 16 | #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) 17 | #define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT)) 18 | #define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT)) 19 | 20 | #define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0) 21 | #define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0) 22 | #define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0) 23 | #define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0) 24 | 25 | 26 | //custom NSLog 27 | #ifdef DEBUG 28 | # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 29 | #else 30 | # define DLog(...) 31 | #endif 32 | 33 | #endif /* MangoMacro_h */ 34 | -------------------------------------------------------------------------------- /UIView+Tools/UIView+Tools.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Tools.h 3 | // shike 4 | // 5 | // Created by Mango on 14/12/12. 6 | // Copyright (c) 2014年 shixun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+AnimationExtensions.h" 11 | 12 | @interface UIView (Tools) 13 | 14 | //将正方形的View裁剪为圆形 15 | - (void)ClipSquareViewToRound; 16 | 17 | //裁剪图片圆角 比直接使用cornerRadius更高效 18 | + (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius usingImage:(UIImage *)original 19 | 20 | /** 21 | * 将UIView转换为image 22 | * 23 | * @param frame 要显示的部分 24 | * 25 | */ 26 | - (UIImage *) renderWithBounds:(CGRect)frame; 27 | 28 | //添加边框 29 | - (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; 30 | 31 | - (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; 32 | 33 | - (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; 34 | 35 | - (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; 36 | 37 | //anmation helper 38 | //请使用UIView+AnimationExtensions.h 39 | /** 40 | * 旋转view 41 | * @param angle 弧度:PI = 360度 42 | */ 43 | - (void)rotateViewWithAngle:(CGFloat)angle andDuration:(CGFloat)duration; 44 | 45 | 46 | //设置anchorPoint,不改变origin 47 | - (void)setAnchorPointAndRemainOrigin:(CGPoint)anchorPoint; 48 | 49 | //封装gestureRecognizer到UIView中,用的时候直接把需触发的block传入即可 50 | - (void)touchEndedBlock:(void(^)(UIView *selfView))block; 51 | 52 | - (void)touchEndedGesture; 53 | 54 | - (void)longPressEndedBlock:(void(^)(UIView *selfView))block; 55 | 56 | - (void)longPressEndedGesture:(UIGestureRecognizer*)gesture; 57 | @end 58 | 59 | 60 | @interface UIImage (Tools) 61 | - (UIImage *)drawImage:(UIImage *)inputImage inRect:(CGRect)frame; 62 | @end 63 | -------------------------------------------------------------------------------- /NSAttributedString+Attributes/NSAttributedString+Attributes.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+Attributes.h 3 | // A category for NSAttributedString and NSMutableAttributedString to easily get or set sub-attributes. 4 | // 5 | // Created by Shilo White on 9/22/13. 6 | // Copyright (c) 2013 XIDA Design & Technik. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSAttributedString (Attributes) 12 | 13 | @property (nonatomic, readonly) UIFont *defaultFont; 14 | 15 | - (UIFont *)fontAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range; 16 | - (NSString *)fontNameAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range; 17 | - (CGFloat)fontSizeAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range; 18 | - (BOOL)boldAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range; 19 | - (BOOL)italicAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range; 20 | 21 | - (UIFont *)fontAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit; 22 | - (NSString *)fontNameAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit; 23 | - (CGFloat)fontSizeAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit; 24 | - (BOOL)boldAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit; 25 | - (BOOL)italicAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit; 26 | 27 | @end 28 | 29 | 30 | @interface NSMutableAttributedString (Attributes) 31 | 32 | - (void)addFont:(UIFont *)font range:(NSRange)range; 33 | - (void)addFontName:(NSString *)fontName range:(NSRange)range; 34 | - (void)addFontSize:(CGFloat)fontSize range:(NSRange)range; 35 | - (void)addBold:(BOOL)bold range:(NSRange)range; 36 | - (void)addItalic:(BOOL)italic range:(NSRange)range; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /HudTools.m: -------------------------------------------------------------------------------- 1 | // 2 | // shike 3 | // 4 | // Copyright (c) 2014年 shixun. All rights reserved. 5 | // 6 | 7 | #import "HudTools.h" 8 | #import "SVProgressHUD.h" 9 | 10 | @interface HudTools() 11 | 12 | @property (nonatomic,strong) NSTimer *timer; 13 | @property (nonatomic,strong) NSDateFormatter *dateFormatter; 14 | 15 | @end 16 | 17 | 18 | @implementation HudTools 19 | 20 | - (id)init 21 | { 22 | self = [super init]; 23 | if (self) { 24 | _dateFormatter = [[NSDateFormatter alloc] init]; 25 | 26 | } 27 | return self; 28 | } 29 | 30 | + (HudTools *)shareInstance 31 | { 32 | static HudTools *g_tools = nil; 33 | static dispatch_once_t onceToken; 34 | dispatch_once(&onceToken, ^{ 35 | g_tools = [[HudTools alloc] init]; 36 | 37 | }); 38 | 39 | return g_tools; 40 | } 41 | 42 | - (void)dealloc 43 | { 44 | [_timer invalidate]; 45 | _timer = nil; 46 | } 47 | 48 | + (void)showStatusWithString:(NSString *)string 49 | { 50 | [SVProgressHUD showWithStatus:string maskType:SVProgressHUDMaskTypeClear]; 51 | } 52 | 53 | + (void)dismiss 54 | { 55 | [SVProgressHUD dismiss]; 56 | } 57 | 58 | + (void)showSuccessWithString:(NSString *)string 59 | { 60 | [SVProgressHUD showSuccessWithStatus:string]; 61 | 62 | HudTools *tools = [HudTools shareInstance]; 63 | [tools.timer invalidate]; 64 | tools.timer = nil; 65 | tools.timer = [NSTimer timerWithTimeInterval:1.5 target:tools selector:@selector(dismiss) userInfo:nil repeats:NO]; 66 | 67 | } 68 | 69 | + (void)showErrorWithString:(NSString *)string 70 | { 71 | [SVProgressHUD showErrorWithStatus:string]; 72 | HudTools *tools = [HudTools shareInstance]; 73 | [tools.timer invalidate]; 74 | tools.timer = nil; 75 | tools.timer = [NSTimer timerWithTimeInterval:1.5 target:tools selector:@selector(dismiss) userInfo:nil repeats:NO]; 76 | } 77 | 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /MangoLog/MangoLog.m: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Created by Mango on 15/7/24. 4 | // 5 | 6 | #import "MangoLog.h" 7 | 8 | @implementation MangoLog 9 | 10 | + (void)writeLogString:(NSString *)logString 11 | { 12 | //格式化字符串 添加日期 13 | /** 示例: 14 | * <2015-07-24 11:21:57 +0000 15 | -[AppDelegate applicationDidFinishLaunching:] [Line 20] 16 | hello world> 17 | */ 18 | logString = [NSString stringWithFormat:@"<\n %@\n%@ \n>\n",[NSDate date],logString]; 19 | 20 | NSFileManager *fileManager = [NSFileManager defaultManager]; 21 | NSURL *document = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; 22 | NSURL *directory = [document URLByAppendingPathComponent:@"mangoLog"]; 23 | [fileManager createDirectoryAtURL:directory withIntermediateDirectories:YES attributes:nil error:nil]; 24 | NSURL *textPath = [directory URLByAppendingPathComponent:@"mangoLog.txt"]; 25 | 26 | if (![fileManager fileExistsAtPath:[textPath path]]) { 27 | 28 | //dispatch_barrier处理单一资源多读单写 29 | dispatch_barrier_async([self sharedQueue], ^{ 30 | 31 | [[logString dataUsingEncoding:NSUTF8StringEncoding] writeToURL:textPath atomically:YES]; 32 | }); 33 | }else{ 34 | 35 | dispatch_barrier_async([self sharedQueue], ^{ 36 | NSFileHandle *handel = [NSFileHandle fileHandleForWritingToURL:textPath error:nil]; 37 | [handel truncateFileAtOffset:[handel seekToEndOfFile]]; 38 | [handel writeData:[logString dataUsingEncoding:NSUTF8StringEncoding]]; 39 | [handel closeFile]; 40 | }); 41 | } 42 | 43 | } 44 | 45 | + (dispatch_queue_t)sharedQueue 46 | { 47 | static dispatch_once_t onceToken; 48 | static dispatch_queue_t sharedQueue; 49 | dispatch_once(&onceToken, ^{ 50 | sharedQueue = dispatch_queue_create([@"mango.barrierQueue" UTF8String], DISPATCH_QUEUE_CONCURRENT); 51 | }); 52 | return sharedQueue; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MangoTools 2 | 3 | 个人收集整理与编写维护的一个 iOS 开发工具库 4 | 5 | ### 1.UIView+Tools 6 | 7 | **recognizer 封装** 8 | 9 | 封装了 UITapGestureRecognizer 等 Recognizer,使用 Block 作为动作触发的回调。 10 | 11 | **layer** 12 | 13 | 便捷地修改 UIView 的 layer 属性,添加不同方向的 border,裁剪为圆。 14 | 15 | ### 2.NSDate+Utilities 16 | 17 | 便捷的时间对比与计算。 18 | 19 | 例如: 20 | 21 | ```obj-c 22 | - (BOOL) isToday; 23 | - (BOOL) isTomorrow; 24 | - (BOOL) isYesterday; 25 | - (BOOL) isTheDayAfterTomorrow; 26 | ``` 27 | 28 | ### 3.[JZLocationConverter](https://github.com/JackZhouCn/JZLocationConverter) 29 | 30 | 便捷的地理位置坐标转换器,将火星坐标转到地球坐标等便捷中国特色功能 31 | 32 | ### 4.HudTools 33 | 34 | 便捷的hud通知调用,全部通过类方法调用。方便快捷。 35 | 36 | ### 5.NSString+Tools.h 37 | 38 | 一些检测 String 的便捷方法,封装了正则匹配等一些匹配。 39 | 40 | ```objective-c 41 | - (BOOL)isMobileNumber:(NSString *)mobileNum 42 | - (BOOL)isCarNumber; 43 | - (BOOL)isURL; 44 | + (NSURL *)HTTPURLFromString:(NSString *)string; 45 | ``` 46 | 47 | ### 6.NSObject+Macro 48 | 49 | 一些常用的宏: 50 | 51 | 例如检测设备 52 | 53 | ```objective-c 54 | #define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0) 55 | #define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0) 56 | #define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0) 57 | ``` 58 | 59 | 定制 NSLog: 60 | 61 | ```objective-c 62 | #ifdef DEBUG 63 | # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 64 | #else 65 | # define DLog(...) 66 | #endif 67 | ``` 68 | 69 | ### 7.EXTScope 70 | 71 | 来自 [libextobjc](https://github.com/jspahrsummers/libextobjc) 中的一个模块。感谢它为我们带来方便打破 block 循环引用的工具。 72 | 73 | 用法: 74 | 75 | ```objective-c 76 | @weakify(self) 77 | [self.context performBlock:^{ 78 | // Analog to strongSelf in previous code snippet. 79 | @strongify(self) 80 | 81 | // You can just reference self as you normally would. Hurray. 82 | NSError *error; 83 | [self.context save:&error]; 84 | 85 | // Do something 86 | }]; 87 | ``` 88 | 89 | 延伸: 90 | 91 | [iOS 夯实:ARC 时代的内存管理](https://github.com/100mango/zen/blob/master/iOS%E5%A4%AF%E5%AE%9E%EF%BC%9AARC%E6%97%B6%E4%BB%A3%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/%23iOS%E5%A4%AF%E5%AE%9E%EF%BC%9AARC%E6%97%B6%E4%BB%A3%E7%9A%84%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86.md) 92 | 93 | ### 8.MangoLog 94 | 95 | 简单的日志工具。直接通过 LOG 保存 Debug 信息到文件。 96 | 97 | 已确保线程安全,简单易扩展。 98 | -------------------------------------------------------------------------------- /UIView+Tools/UILabel+Tools.m: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel+Tools.m 3 | // 4 | // Created by Mango on 15/12/4. 5 | // Copyright © 2015年 Mango. All rights reserved. 6 | // 7 | 8 | #import "UILabel+Tools.h" 9 | 10 | @implementation UILabel (Tools) 11 | 12 | - (void)setText:(NSString *)text highlightKeyWord:(NSArray *)keywords highlightColor:(UIColor*)color{ 13 | 14 | if (text.length > 0) { 15 | text = [text stringByReplacingOccurrencesOfString:@"\n" withString:@""]; 16 | } 17 | 18 | if ((text.length <= 0) || (keywords.count <= 0)) { 19 | self.attributedText = nil; 20 | self.text = text; 21 | return; 22 | } 23 | 24 | NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:text]; 25 | for (NSString *keyword in keywords) { 26 | BOOL endString = NO; 27 | NSUInteger pos = 0; 28 | NSString *tempStr = text; 29 | NSUInteger tempPos = 0; 30 | do { 31 | NSRange boldRange = [tempStr rangeOfString:keyword options:NSCaseInsensitiveSearch]; 32 | if (boldRange.length > 0) { 33 | [attributeStr addAttribute:(NSString *)NSForegroundColorAttributeName value:color range:NSMakeRange(tempPos + boldRange.location, boldRange.length)]; 34 | 35 | pos = boldRange.location + boldRange.length; 36 | tempPos += pos; 37 | tempStr = [tempStr substringFromIndex:pos]; 38 | } else { 39 | endString = YES; 40 | } 41 | } while (!endString && tempPos < text.length); 42 | 43 | } 44 | self.text = nil; 45 | self.attributedText = attributeStr; 46 | } 47 | 48 | - (void)adjustFontSizeToFitBounds 49 | { 50 | //从最大字号放缩到最小字号 51 | int fontSize = 14; 52 | int minFontSize = 1; 53 | 54 | // Fit label width wize 55 | CGSize constraintSize = CGSizeMake(self.frame.size.width, MAXFLOAT); 56 | CGSize textSize; 57 | 58 | do { 59 | self.font = [UIFont fontWithName:self.font.fontName size:fontSize]; 60 | 61 | //获得当前字号所需的label大小 62 | textSize = [self sizeThatFits:constraintSize]; 63 | // 如果估算label大小小于实际Label的大小,则找到,否则缩小字号继续寻找 64 | if( textSize.height <= self.frame.size.height){ 65 | break; 66 | } 67 | 68 | fontSize -= 1; 69 | 70 | } while (fontSize > minFontSize); 71 | 72 | //如果只有一行 则居中 73 | if (floor((textSize.height / self.font.lineHeight)) == 1) { 74 | self.textAlignment = NSTextAlignmentCenter; 75 | }else{ 76 | self.textAlignment = NSTextAlignmentLeft; 77 | } 78 | 79 | } 80 | @end 81 | -------------------------------------------------------------------------------- / NSString+Tools/NSString+Tools.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Tools.m 3 | // Trans 4 | // 5 | // Created by Mango on 15/2/2. 6 | // Copyright (c) 2015年 Mango. All rights reserved. 7 | // 8 | 9 | #import "NSString+Tools.h" 10 | 11 | @implementation NSString (Tools) 12 | 13 | - (BOOL)isMobileNumber:(NSString *)mobileNum 14 | { 15 | /** 16 | * 手机号码 17 | * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 18 | * 联通:130,131,132,152,155,156,185,186 19 | * 电信:133,1349,153,180,189 20 | */ 21 | NSString * MOBILE = @"^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$"; 22 | /** 23 | 10 * 中国移动:China Mobile 24 | 11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188 25 | 12 */ 26 | NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d)\\d{7}$"; 27 | /** 28 | 15 * 中国联通:China Unicom 29 | 16 * 130,131,132,152,155,156,185,186 30 | 17 */ 31 | NSString * CU = @"^1(3[0-2]|5[256]|8[56])\\d{8}$"; 32 | /** 33 | 20 * 中国电信:China Telecom 34 | 21 * 133,1349,153,180,189 35 | 22 */ 36 | NSString * CT = @"^1((33|53|8[09])[0-9]|349)\\d{7}$"; 37 | /** 38 | 25 * 大陆地区固话及小灵通 39 | 26 * 区号:010,020,021,022,023,024,025,027,028,029 40 | 27 * 号码:七位或八位 41 | 28 */ 42 | // NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$"; 43 | 44 | NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE]; 45 | NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM]; 46 | NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU]; 47 | NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT]; 48 | 49 | if (([regextestmobile evaluateWithObject:mobileNum] == YES) 50 | || ([regextestcm evaluateWithObject:mobileNum] == YES) 51 | || ([regextestct evaluateWithObject:mobileNum] == YES) 52 | || ([regextestcu evaluateWithObject:mobileNum] == YES)) 53 | { 54 | return YES; 55 | } 56 | else 57 | { 58 | return NO; 59 | } 60 | } 61 | 62 | - (BOOL)isCarNumber 63 | { 64 | NSString *carRegex = @"^[A-Za-z_0-9]{5}$"; 65 | NSPredicate *carTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",carRegex]; 66 | return [carTest evaluateWithObject:self]; 67 | } 68 | 69 | - (BOOL)isURL 70 | { 71 | NSURL *url = [NSURL URLWithString:self]; 72 | if (url && url.host) { 73 | return YES; 74 | } 75 | else 76 | { 77 | return NO; 78 | } 79 | } 80 | 81 | +(NSURL *)HTTPURLFromString:(NSString *)string 82 | { 83 | NSString *searchString = @"http"; 84 | NSRange prefixRange = [string rangeOfString:searchString options:(NSCaseInsensitiveSearch | NSAnchoredSearch)]; 85 | 86 | if (prefixRange.length == 4) { 87 | return [NSURL URLWithString:string]; 88 | } 89 | return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", string]]; 90 | 91 | } 92 | 93 | + (NSString *)timeStringFromSeconds:(int)totalSeconds 94 | { 95 | int seconds = totalSeconds % 60; 96 | int minutes = (totalSeconds / 60) % 60; 97 | int hours = totalSeconds / 3600; 98 | 99 | return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds]; 100 | } 101 | @end 102 | -------------------------------------------------------------------------------- /UIView+Tools/UIView+AnimationExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Rafal Sroka 3 | // 4 | // License CC0. 5 | // This is free and unencumbered software released into the public domain. 6 | // 7 | // Anyone is free to copy, modify, publish, use, compile, sell, or 8 | // distribute this software, either in source code form or as a compiled 9 | // binary, for any purpose, commercial or non-commercial, and by any means. 10 | // 11 | 12 | 13 | /** 14 | @brief Direction of flip animation. 15 | */ 16 | typedef NS_ENUM(NSUInteger, UIViewAnimationFlipDirection) 17 | { 18 | UIViewAnimationFlipDirectionFromTop, 19 | UIViewAnimationFlipDirectionFromLeft, 20 | UIViewAnimationFlipDirectionFromRight, 21 | UIViewAnimationFlipDirectionFromBottom, 22 | }; 23 | 24 | 25 | /** 26 | @brief Direction of rotation animation. 27 | */ 28 | typedef NS_ENUM(NSUInteger, UIViewAnimationRotationDirection) 29 | { 30 | UIViewAnimationRotationDirectionRight, 31 | UIViewAnimationRotationDirectionLeft 32 | }; 33 | 34 | 35 | @interface UIView (AnimationExtensions) 36 | 37 | /** 38 | @brief Shakes the view horizontally for a short period of time. 39 | */ 40 | - (void)shakeHorizontally; 41 | 42 | 43 | /** 44 | @brief Shakes the view vertically for a short period of time. 45 | */ 46 | - (void)shakeVertically; 47 | 48 | 49 | /** 50 | @brief Adds a motion effect to the view. Similar effect can be seen in the 51 | background of the Home Screen on iOS 7. 52 | @note Motion effects are available starting from iOS 7. Calling this method on 53 | older iOS will be ignored. 54 | */ 55 | - (void)applyMotionEffects; 56 | 57 | 58 | /** 59 | @brief Performs a pulsing scale animation on a view. 60 | @param duration - duration of the animation 61 | @param repeat - pass YES for the animation to repeat. 62 | */ 63 | - (void)pulseToSize:(CGFloat)scale 64 | duration:(NSTimeInterval)duration 65 | repeat:(BOOL)repeat; 66 | 67 | 68 | /** 69 | @brief Performs a 3D-like flip animation of the view around center X or Y axis. 70 | @param duration - total time of the animation. 71 | @param direction - direction of the flip movement. 72 | @param repeatCount - number of repetitions of the animation. Pass HUGE_VALF to repeat forever. 73 | @param shouldAutoreverse - pass YES to make the animation reverse when it reaches the end. 74 | */ 75 | - (void)flipWithDuration:(NSTimeInterval)duration 76 | direction:(UIViewAnimationFlipDirection)direction 77 | repeatCount:(NSUInteger)repeatCount 78 | autoreverse:(BOOL)shouldAutoreverse; 79 | 80 | 81 | /** 82 | @brief Performs a rotation animation of the view around its anchor point. 83 | @param angle - end angle of the rotation. Pass M_PI * 2.0 for full circle rotation. 84 | @param duration - total time of the animation. 85 | @param direction - left or right direction of the rotation. 86 | @param repeatCount - number of repetitions of the animation. Pass HUGE_VALF to repeat forever. 87 | @param shouldAutoreverse - pass YES to make the animation reverse when it reaches the end. 88 | */ 89 | - (void)rotateToAngle:(CGFloat)angle 90 | duration:(NSTimeInterval)duration 91 | direction:(UIViewAnimationRotationDirection)direction 92 | repeatCount:(NSUInteger)repeatCount 93 | autoreverse:(BOOL)shouldAutoreverse; 94 | 95 | 96 | /** 97 | @brief Stops current animations. 98 | */ 99 | - (void)stopAnimation; 100 | 101 | 102 | /** 103 | @brief Checks if the view is being animated. 104 | */ 105 | - (BOOL)isBeingAnimated; 106 | 107 | 108 | @end -------------------------------------------------------------------------------- /Swift/UIView-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewExtension.swift 3 | // 3D 4 | // 5 | // Created by Mango on 15/12/7. 6 | // Copyright © 2015年 Mango. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //MARK: UIView 12 | 13 | public extension UIView{ 14 | 15 | public var width: CGFloat { 16 | get { return self.frame.size.width } 17 | set { self.frame.size.width = newValue } 18 | } 19 | 20 | public var height: CGFloat { 21 | get { return self.frame.size.height } 22 | set { self.frame.size.height = newValue } 23 | } 24 | 25 | public var top: CGFloat { 26 | get { return self.frame.origin.y } 27 | set { self.frame.origin.y = newValue } 28 | } 29 | public var right: CGFloat { 30 | get { return self.frame.origin.x + self.width } 31 | set { self.frame.origin.x = newValue - self.width } 32 | } 33 | public var bottom: CGFloat { 34 | get { return self.frame.origin.y + self.height } 35 | set { self.frame.origin.y = newValue - self.height } 36 | } 37 | public var left: CGFloat { 38 | get { return self.frame.origin.x } 39 | set { self.frame.origin.x = newValue } 40 | } 41 | 42 | public var centerX: CGFloat{ 43 | get { return self.center.x } 44 | set { self.center = CGPoint(x: newValue,y: self.centerY) } 45 | } 46 | public var centerY: CGFloat { 47 | get { return self.center.y } 48 | set { self.center = CGPoint(x: self.centerX,y: newValue) } 49 | } 50 | 51 | public var origin: CGPoint { 52 | set { self.frame.origin = newValue } 53 | get { return self.frame.origin } 54 | } 55 | public var size: CGSize { 56 | set { self.frame.size = newValue } 57 | get { return self.frame.size } 58 | } 59 | } 60 | 61 | extension UIView { 62 | var parentViewController: UIViewController? { 63 | var parentResponder: UIResponder? = self 64 | while let responder = parentResponder { 65 | parentResponder = responder.nextResponder() 66 | if let viewController = parentResponder as? UIViewController { 67 | return viewController 68 | } 69 | } 70 | return nil 71 | } 72 | } 73 | 74 | //MARK: UITableView,UITableViewCell,UICollectionView,UICollectionViewCell 75 | 76 | public extension UITableView{ 77 | public func registerClass(cellType:UITableViewCell.Type){ 78 | registerClass(cellType, forCellReuseIdentifier: cellType.defaultReuseIdentifier) 79 | } 80 | 81 | public func dequeueReusableCellForIndexPath(indexPath: NSIndexPath) -> T { 82 | guard let cell = self.dequeueReusableCellWithIdentifier(T.defaultReuseIdentifier , forIndexPath: indexPath) as? T else { 83 | fatalError( "Failed to dequeue a cell with identifier \(T.defaultReuseIdentifier). Ensure you have registered the cell." ) 84 | } 85 | 86 | return cell 87 | } 88 | } 89 | 90 | public extension UITableViewCell{ 91 | public static var defaultReuseIdentifier:String{ 92 | return String(self) 93 | } 94 | } 95 | 96 | public extension UICollectionView{ 97 | public func registerClass(cellType:UICollectionViewCell.Type){ 98 | registerClass(cellType, forCellWithReuseIdentifier: cellType.defaultReuseIdentifier) 99 | } 100 | 101 | public func dequeueReusableCellForIndexPath(indexPath: NSIndexPath) -> T { 102 | guard let cell = self.dequeueReusableCellWithReuseIdentifier(T.defaultReuseIdentifier, forIndexPath: indexPath) as? T else { 103 | fatalError( "Failed to dequeue a cell with identifier \(T.defaultReuseIdentifier). Ensure you have registered the cell" ) 104 | } 105 | 106 | return cell 107 | } 108 | } 109 | 110 | public extension UICollectionViewCell{ 111 | public static var defaultReuseIdentifier:String{ 112 | return String(self) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /NSDate+Utilities/NSDate+Utilities.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | #define D_MINUTE 60 5 | #define D_HOUR 3600 6 | #define D_DAY 86400 7 | #define D_WEEK 604800 8 | #define D_YEAR 31556926 9 | 10 | @interface NSDate (Utilities) 11 | + (NSCalendar *) currentCalendar; // avoid bottlenecks 12 | 13 | // Relative dates from the current date 14 | + (NSDate *) dateTomorrow; 15 | + (NSDate *) dateYesterday; 16 | + (NSDate *) dateWithDaysFromNow: (NSInteger) days; 17 | + (NSDate *) dateWithDaysBeforeNow: (NSInteger) days; 18 | + (NSDate *) dateWithHoursFromNow: (NSInteger) dHours; 19 | + (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours; 20 | + (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes; 21 | + (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes; 22 | 23 | // Short string utilities 24 | - (NSString *) stringWithDateStyle: (NSDateFormatterStyle) dateStyle timeStyle: (NSDateFormatterStyle) timeStyle; 25 | - (NSString *) stringWithFormat: (NSString *) format; 26 | @property (nonatomic, readonly) NSString *shortString; 27 | @property (nonatomic, readonly) NSString *shortDateString; 28 | @property (nonatomic, readonly) NSString *shortTimeString; 29 | @property (nonatomic, readonly) NSString *mediumString; 30 | @property (nonatomic, readonly) NSString *mediumDateString; 31 | @property (nonatomic, readonly) NSString *mediumTimeString; 32 | @property (nonatomic, readonly) NSString *longString; 33 | @property (nonatomic, readonly) NSString *longDateString; 34 | @property (nonatomic, readonly) NSString *longTimeString; 35 | 36 | // Comparing dates 37 | - (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate; 38 | 39 | - (BOOL) isToday; 40 | - (BOOL) isTomorrow; 41 | - (BOOL) isYesterday; 42 | //新添加 43 | - (BOOL) isTheDayAfterTomorrow; 44 | 45 | - (BOOL) isSameWeekAsDate: (NSDate *) aDate; 46 | - (BOOL) isThisWeek; 47 | - (BOOL) isNextWeek; 48 | - (BOOL) isLastWeek; 49 | 50 | - (BOOL) isSameMonthAsDate: (NSDate *) aDate; 51 | - (BOOL) isThisMonth; 52 | - (BOOL) isNextMonth; 53 | - (BOOL) isLastMonth; 54 | 55 | - (BOOL) isSameYearAsDate: (NSDate *) aDate; 56 | - (BOOL) isThisYear; 57 | - (BOOL) isNextYear; 58 | - (BOOL) isLastYear; 59 | 60 | - (BOOL) isEarlierThanDate: (NSDate *) aDate; 61 | - (BOOL) isLaterThanDate: (NSDate *) aDate; 62 | 63 | - (BOOL) isInFuture; 64 | - (BOOL) isInPast; 65 | 66 | // Date roles 67 | - (BOOL) isTypicallyWorkday; 68 | - (BOOL) isTypicallyWeekend; 69 | 70 | // Adjusting dates 71 | - (NSDate *) dateByAddingYears: (NSInteger) dYears; 72 | - (NSDate *) dateBySubtractingYears: (NSInteger) dYears; 73 | - (NSDate *) dateByAddingMonths: (NSInteger) dMonths; 74 | - (NSDate *) dateBySubtractingMonths: (NSInteger) dMonths; 75 | - (NSDate *) dateByAddingDays: (NSInteger) dDays; 76 | - (NSDate *) dateBySubtractingDays: (NSInteger) dDays; 77 | - (NSDate *) dateByAddingHours: (NSInteger) dHours; 78 | - (NSDate *) dateBySubtractingHours: (NSInteger) dHours; 79 | - (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes; 80 | - (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes; 81 | 82 | // Date extremes 83 | - (NSDate *) dateAtStartOfDay; 84 | - (NSDate *) dateAtEndOfDay; 85 | 86 | // Retrieving intervals 87 | - (NSInteger) minutesAfterDate: (NSDate *) aDate; 88 | - (NSInteger) minutesBeforeDate: (NSDate *) aDate; 89 | - (NSInteger) hoursAfterDate: (NSDate *) aDate; 90 | - (NSInteger) hoursBeforeDate: (NSDate *) aDate; 91 | - (NSInteger) daysAfterDate: (NSDate *) aDate; 92 | - (NSInteger) daysBeforeDate: (NSDate *) aDate; 93 | - (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate; 94 | 95 | // Decomposing dates 96 | @property (readonly) NSInteger nearestHour; 97 | @property (readonly) NSInteger hour; 98 | @property (readonly) NSInteger minute; 99 | @property (readonly) NSInteger seconds; 100 | @property (readonly) NSInteger day; 101 | @property (readonly) NSInteger month; 102 | @property (readonly) NSInteger week; 103 | @property (readonly) NSInteger weekday; 104 | @property (readonly) NSInteger nthWeekday; // e.g. 2nd Tuesday of the month == 2 105 | @property (readonly) NSInteger year; 106 | @end 107 | -------------------------------------------------------------------------------- /EXTScope/EXTScope.h: -------------------------------------------------------------------------------- 1 | // 2 | // EXTScope.h 3 | // extobjc 4 | // 5 | // Created by Justin Spahr-Summers on 2011-05-04. 6 | // Copyright (C) 2012 Justin Spahr-Summers. 7 | // Released under the MIT license. 8 | // 9 | 10 | #import "metamacros.h" 11 | 12 | /** 13 | * \@onExit defines some code to be executed when the current scope exits. The 14 | * code must be enclosed in braces and terminated with a semicolon, and will be 15 | * executed regardless of how the scope is exited, including from exceptions, 16 | * \c goto, \c return, \c break, and \c continue. 17 | * 18 | * Provided code will go into a block to be executed later. Keep this in mind as 19 | * it pertains to memory management, restrictions on assignment, etc. Because 20 | * the code is used within a block, \c return is a legal (though perhaps 21 | * confusing) way to exit the cleanup block early. 22 | * 23 | * Multiple \@onExit statements in the same scope are executed in reverse 24 | * lexical order. This helps when pairing resource acquisition with \@onExit 25 | * statements, as it guarantees teardown in the opposite order of acquisition. 26 | * 27 | * @note This statement cannot be used within scopes defined without braces 28 | * (like a one line \c if). In practice, this is not an issue, since \@onExit is 29 | * a useless construct in such a case anyways. 30 | */ 31 | #define onExit \ 32 | ext_keywordify \ 33 | __strong ext_cleanupBlock_t metamacro_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^ 34 | 35 | /** 36 | * Creates \c __weak shadow variables for each of the variables provided as 37 | * arguments, which can later be made strong again with #strongify. 38 | * 39 | * This is typically used to weakly reference variables in a block, but then 40 | * ensure that the variables stay alive during the actual execution of the block 41 | * (if they were live upon entry). 42 | * 43 | * See #strongify for an example of usage. 44 | */ 45 | #define weakify(...) \ 46 | ext_keywordify \ 47 | metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__) 48 | 49 | /** 50 | * Like #weakify, but uses \c __unsafe_unretained instead, for targets or 51 | * classes that do not support weak references. 52 | */ 53 | #define unsafeify(...) \ 54 | ext_keywordify \ 55 | metamacro_foreach_cxt(ext_weakify_,, __unsafe_unretained, __VA_ARGS__) 56 | 57 | /** 58 | * Strongly references each of the variables provided as arguments, which must 59 | * have previously been passed to #weakify. 60 | * 61 | * The strong references created will shadow the original variable names, such 62 | * that the original names can be used without issue (and a significantly 63 | * reduced risk of retain cycles) in the current scope. 64 | * 65 | * @code 66 | 67 | id foo = [[NSObject alloc] init]; 68 | id bar = [[NSObject alloc] init]; 69 | 70 | @weakify(foo, bar); 71 | 72 | // this block will not keep 'foo' or 'bar' alive 73 | BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){ 74 | // but now, upon entry, 'foo' and 'bar' will stay alive until the block has 75 | // finished executing 76 | @strongify(foo, bar); 77 | 78 | return [foo isEqual:obj] || [bar isEqual:obj]; 79 | }; 80 | 81 | * @endcode 82 | */ 83 | #define strongify(...) \ 84 | ext_keywordify \ 85 | _Pragma("clang diagnostic push") \ 86 | _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 87 | metamacro_foreach(ext_strongify_,, __VA_ARGS__) \ 88 | _Pragma("clang diagnostic pop") 89 | 90 | /*** implementation details follow ***/ 91 | typedef void (^ext_cleanupBlock_t)(); 92 | 93 | void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block); 94 | 95 | #define ext_weakify_(INDEX, CONTEXT, VAR) \ 96 | CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR); 97 | 98 | #define ext_strongify_(INDEX, VAR) \ 99 | __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_); 100 | 101 | // Details about the choice of backing keyword: 102 | // 103 | // The use of @try/@catch/@finally can cause the compiler to suppress 104 | // return-type warnings. 105 | // The use of @autoreleasepool {} is not optimized away by the compiler, 106 | // resulting in superfluous creation of autorelease pools. 107 | // 108 | // Since neither option is perfect, and with no other alternatives, the 109 | // compromise is to use @autorelease in DEBUG builds to maintain compiler 110 | // analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary 111 | // autorelease pools. 112 | #if DEBUG 113 | #define ext_keywordify autoreleasepool {} 114 | #else 115 | #define ext_keywordify try {} @catch (...) {} 116 | #endif 117 | -------------------------------------------------------------------------------- /UIView+Tools/UIView+AnimationExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Rafal Sroka 3 | // 4 | // License CC0. 5 | // This is free and unencumbered software released into the public domain. 6 | // 7 | // Anyone is free to copy, modify, publish, use, compile, sell, or 8 | // distribute this software, either in source code form or as a compiled 9 | // binary, for any purpose, commercial or non-commercial, and by any means. 10 | // 11 | 12 | 13 | #import "UIView+AnimationExtensions.h" 14 | 15 | 16 | @implementation UIView (AnimationExtensions) 17 | 18 | 19 | - (void)shakeHorizontally 20 | { 21 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; 22 | 23 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 24 | animation.duration = 0.5; 25 | animation.values = @[@(-12), @(12), @(-8), @(8), @(-4), @(4), @(0) ]; 26 | 27 | [self.layer addAnimation:animation forKey:@"shake"]; 28 | } 29 | 30 | 31 | - (void)shakeVertically 32 | { 33 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"]; 34 | 35 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 36 | animation.duration = 0.5; 37 | animation.values = @[@(-12), @(12), @(-8), @(8), @(-4), @(4), @(0) ]; 38 | 39 | [self.layer addAnimation:animation forKey:@"shake"]; 40 | } 41 | 42 | 43 | - (void)applyMotionEffects 44 | { 45 | // Motion effects are available starting from iOS 7. 46 | if (([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending)) 47 | { 48 | 49 | UIInterpolatingMotionEffect *horizontalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" 50 | type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; 51 | horizontalEffect.minimumRelativeValue = @(-10.0f); 52 | horizontalEffect.maximumRelativeValue = @( 10.0f); 53 | UIInterpolatingMotionEffect *verticalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" 54 | type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; 55 | verticalEffect.minimumRelativeValue = @(-10.0f); 56 | verticalEffect.maximumRelativeValue = @( 10.0f); 57 | UIMotionEffectGroup *motionEffectGroup = [[UIMotionEffectGroup alloc] init]; 58 | motionEffectGroup.motionEffects = @[horizontalEffect, verticalEffect]; 59 | 60 | [self addMotionEffect:motionEffectGroup]; 61 | } 62 | } 63 | 64 | 65 | - (void)pulseToSize:(CGFloat)scale 66 | duration:(NSTimeInterval)duration 67 | repeat:(BOOL)repeat 68 | { 69 | CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; 70 | 71 | pulseAnimation.duration = duration; 72 | pulseAnimation.toValue = [NSNumber numberWithFloat:scale]; 73 | pulseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 74 | pulseAnimation.autoreverses = YES; 75 | pulseAnimation.repeatCount = repeat ? HUGE_VALF : 0; 76 | 77 | [self.layer addAnimation:pulseAnimation 78 | forKey:@"pulse"]; 79 | } 80 | 81 | 82 | - (void)flipWithDuration:(NSTimeInterval)duration 83 | direction:(UIViewAnimationFlipDirection)direction 84 | repeatCount:(NSUInteger)repeatCount 85 | autoreverse:(BOOL)shouldAutoreverse 86 | { 87 | NSString *subtype = nil; 88 | 89 | switch (direction) 90 | { 91 | case UIViewAnimationFlipDirectionFromTop: 92 | subtype = @"fromTop"; 93 | break; 94 | case UIViewAnimationFlipDirectionFromLeft: 95 | subtype = @"fromLeft"; 96 | break; 97 | case UIViewAnimationFlipDirectionFromBottom: 98 | subtype = @"fromBottom"; 99 | break; 100 | case UIViewAnimationFlipDirectionFromRight: 101 | default: 102 | subtype = @"fromRight"; 103 | break; 104 | } 105 | 106 | CATransition *transition = [CATransition animation]; 107 | 108 | transition.startProgress = 0; 109 | transition.endProgress = 1.0; 110 | transition.type = @"flip"; 111 | transition.subtype = subtype; 112 | transition.duration = duration; 113 | transition.repeatCount = repeatCount; 114 | transition.autoreverses = shouldAutoreverse; 115 | 116 | [self.layer addAnimation:transition 117 | forKey:@"spin"]; 118 | } 119 | 120 | 121 | - (void)rotateToAngle:(CGFloat)angle 122 | duration:(NSTimeInterval)duration 123 | direction:(UIViewAnimationRotationDirection)direction 124 | repeatCount:(NSUInteger)repeatCount 125 | autoreverse:(BOOL)shouldAutoreverse; 126 | { 127 | CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 128 | 129 | rotationAnimation.toValue = @(direction == UIViewAnimationRotationDirectionRight ? angle : -angle); 130 | rotationAnimation.duration = duration; 131 | rotationAnimation.autoreverses = shouldAutoreverse; 132 | rotationAnimation.repeatCount = repeatCount; 133 | rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 134 | 135 | [self.layer addAnimation:rotationAnimation 136 | forKey:@"transform.rotation.z"]; 137 | } 138 | 139 | 140 | - (void)stopAnimation 141 | { 142 | [CATransaction begin]; 143 | [self.layer removeAllAnimations]; 144 | [CATransaction commit]; 145 | 146 | [CATransaction flush]; 147 | } 148 | 149 | 150 | - (BOOL)isBeingAnimated 151 | { 152 | return [self.layer.animationKeys count]; 153 | } 154 | 155 | 156 | @end -------------------------------------------------------------------------------- /UIView+Tools/UIView+Tools.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Tools.m 3 | // shike 4 | // 5 | // Created by Mango on 14/12/12. 6 | // Copyright (c) 2014年 shixun. All rights reserved. 7 | // 8 | 9 | #import "UIView+Tools.h" 10 | #import 11 | static const void *BGTouchEndedViewBlockKey = &BGTouchEndedViewBlockKey; 12 | static const void *BGTouchLongPressEndedViewBlockKey = &BGTouchLongPressEndedViewBlockKey; 13 | 14 | 15 | @implementation UIView (Tools) 16 | 17 | - (void)ClipSquareViewToRound 18 | { 19 | if (self.frame.size.width == self.frame.size.height) 20 | { 21 | self.layer.cornerRadius = self.frame.size.width/2; 22 | } 23 | } 24 | 25 | + (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius usingImage:(UIImage *)original 26 | { 27 | CGRect frame = CGRectMake(0, 0, original.size.width, original.size.height); 28 | 29 | // Begin a new image that will be the new image with the rounded corners 30 | // (here with the size of an UIImageView) 31 | UIGraphicsBeginImageContextWithOptions(original.size, NO, 1.0); 32 | 33 | // Add a clip before drawing anything, in the shape of an rounded rect 34 | [[UIBezierPath bezierPathWithRoundedRect:frame 35 | cornerRadius:cornerRadius] addClip]; 36 | // Draw your image 37 | [original drawInRect:frame]; 38 | 39 | // Get the image, here setting the UIImageView image 40 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 41 | 42 | // Lets forget about that we were drawing 43 | UIGraphicsEndImageContext(); 44 | 45 | return image; 46 | } 47 | 48 | - (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { 49 | CALayer *border = [CALayer layer]; 50 | border.backgroundColor = color.CGColor; 51 | 52 | border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth); 53 | [self.layer addSublayer:border]; 54 | } 55 | 56 | - (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { 57 | CALayer *border = [CALayer layer]; 58 | border.backgroundColor = color.CGColor; 59 | 60 | border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth); 61 | [self.layer addSublayer:border]; 62 | } 63 | 64 | - (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { 65 | CALayer *border = [CALayer layer]; 66 | border.backgroundColor = color.CGColor; 67 | 68 | border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height); 69 | [self.layer addSublayer:border]; 70 | } 71 | 72 | - (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { 73 | CALayer *border = [CALayer layer]; 74 | border.backgroundColor = color.CGColor; 75 | 76 | border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height); 77 | [self.layer addSublayer:border]; 78 | } 79 | 80 | - (UIImage *)renderWithBounds:(CGRect)frame { 81 | 82 | CGSize imageSize = frame.size; 83 | 84 | UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); 85 | CGContextRef c = UIGraphicsGetCurrentContext(); 86 | 87 | CGContextConcatCTM(c, CGAffineTransformMakeTranslation(-frame.origin.x, -frame.origin.y)); 88 | [self.layer renderInContext:c]; 89 | 90 | UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); 91 | UIGraphicsEndImageContext(); 92 | return screenshot; 93 | 94 | } 95 | 96 | - (void)setAnchorPointAndRemainOrigin:(CGPoint)anchorPoint; 97 | { 98 | CGPoint oldOrigin = self.frame.origin; 99 | self.layer.anchorPoint = anchorPoint; 100 | CGPoint newOrigin = self.frame.origin; 101 | 102 | CGPoint transition; 103 | transition.x = newOrigin.x - oldOrigin.x; 104 | transition.y = newOrigin.y - oldOrigin.y; 105 | 106 | self.center = CGPointMake (self.center.x - transition.x, self.center.y - transition.y); 107 | } 108 | 109 | 110 | #pragma mark -animation 111 | - (void)rotateViewWithAngle:(CGFloat)angle andDuration:(CGFloat)duration 112 | { 113 | 114 | [UIView animateWithDuration:duration animations:^{ 115 | CGAffineTransform oldTransForm = self.transform; 116 | self.transform = CGAffineTransformRotate(oldTransForm, angle); 117 | }]; 118 | } 119 | 120 | #pragma mark -handel action 121 | - (void)touchEndedBlock:(void (^)(UIView *selfView))block 122 | { 123 | self.userInteractionEnabled = YES; 124 | UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self 125 | action:@selector(touchEndedGesture)]; 126 | tapped.numberOfTapsRequired = 1; 127 | [self addGestureRecognizer:tapped]; 128 | objc_setAssociatedObject(self, BGTouchEndedViewBlockKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC); 129 | } 130 | 131 | - (void)touchEndedGesture 132 | { 133 | void(^_touchBlock)(UIView *selfView) = objc_getAssociatedObject(self, BGTouchEndedViewBlockKey); 134 | if (_touchBlock) { 135 | _touchBlock(self); 136 | } 137 | } 138 | 139 | -(void)longPressEndedBlock:(void (^)(UIView *selfView))block 140 | { 141 | self.userInteractionEnabled = YES; 142 | UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressEndedGesture:)]; 143 | longPress.minimumPressDuration = 0.5; 144 | [self addGestureRecognizer:longPress]; 145 | objc_setAssociatedObject(self, BGTouchLongPressEndedViewBlockKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC); 146 | } 147 | 148 | -(void)longPressEndedGesture:(UIGestureRecognizer*)gesture 149 | { 150 | if (gesture.state == UIGestureRecognizerStateBegan) { 151 | void(^_touchBlock)(UIView *selfView) = objc_getAssociatedObject(self, BGTouchLongPressEndedViewBlockKey); 152 | if (_touchBlock) { 153 | _touchBlock(self); 154 | } 155 | } 156 | } 157 | 158 | 159 | @end 160 | 161 | 162 | #pragma mark - UIImage 163 | @implementation UIImage (Tools) 164 | - (UIImage *)drawImage:(UIImage *)inputImage inRect:(CGRect)frame { 165 | UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); 166 | [self drawInRect:CGRectMake(0.0, 0.0, self.size.width, self.size.height)]; 167 | [inputImage drawInRect:frame]; 168 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 169 | UIGraphicsEndImageContext(); 170 | return newImage; 171 | } 172 | @end 173 | -------------------------------------------------------------------------------- /NSAttributedString+Attributes/NSAttributedString+Attributes.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+Attributes.m 3 | // A category for NSAttributedString and NSMutableAttributedString to easily get or set sub-attributes. 4 | // 5 | // Created by Shilo White on 9/22/13. 6 | // Copyright (c) 2013 XIDA Design & Technik. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedString+Attributes.h" 10 | #import 11 | 12 | #define DEFAULT_FONT_NAME @"Helvetica" 13 | #define DEFAULT_FONT_SIZE 12.0f 14 | #define RANGE NSMakeRange(0, self.length) 15 | 16 | @interface UIFont (Attributes) 17 | 18 | + (UIFont *)fontWithFont:(UIFont *)font size:(CGFloat)pointSize; 19 | + (UIFont *)fontWithFont:(UIFont *)font name:(NSString *)fontName; 20 | + (UIFont *)fontWithFont:(UIFont *)font bold:(BOOL)bold; 21 | + (UIFont *)fontWithFont:(UIFont *)font italic:(BOOL)italic; 22 | 23 | @property (nonatomic, readonly) BOOL bold; 24 | @property (nonatomic, readonly) BOOL italic; 25 | 26 | @end 27 | 28 | @implementation NSAttributedString (Attributes) 29 | 30 | - (UIFont *)defaultFont 31 | { 32 | return [UIFont fontWithName:DEFAULT_FONT_NAME size:DEFAULT_FONT_SIZE]; 33 | } 34 | 35 | - (UIFont *)fontAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range 36 | { 37 | return [self fontAtIndex:index longestEffectiveRange:range inRange:RANGE]; 38 | } 39 | 40 | - (NSString *)fontNameAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range 41 | { 42 | return [self fontNameAtIndex:index longestEffectiveRange:range inRange:RANGE]; 43 | } 44 | 45 | - (CGFloat)fontSizeAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range 46 | { 47 | return [self fontSizeAtIndex:index longestEffectiveRange:range inRange:RANGE]; 48 | } 49 | 50 | - (BOOL)boldAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range 51 | { 52 | return [self boldAtIndex:index longestEffectiveRange:range inRange:RANGE]; 53 | } 54 | 55 | - (BOOL)italicAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)range 56 | { 57 | return [self italicAtIndex:index longestEffectiveRange:range inRange:RANGE]; 58 | } 59 | 60 | - (UIFont *)fontAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 61 | { 62 | UIFont *font = [self attribute:NSFontAttributeName atIndex:index longestEffectiveRange:range inRange:rangeLimit]; 63 | return font ? font : self.defaultFont; 64 | } 65 | 66 | - (NSString *)fontNameAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 67 | { 68 | NSString *fontName = [self fontAtIndex:index longestEffectiveRange:range inRange:rangeLimit].fontName; 69 | 70 | while (NSMaxRange(*range) < NSMaxRange(rangeLimit)) 71 | { 72 | NSRange nextRange; 73 | NSString *nextFontName = [self fontAtIndex:NSMaxRange(*range) longestEffectiveRange:&nextRange inRange:rangeLimit].fontName; 74 | if (![fontName isEqualToString:nextFontName]) break; 75 | (*range).length += nextRange.length; 76 | } 77 | 78 | return fontName; 79 | } 80 | 81 | - (CGFloat)fontSizeAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 82 | { 83 | CGFloat fontSize = [self fontAtIndex:index longestEffectiveRange:range inRange:rangeLimit].pointSize; 84 | 85 | while (NSMaxRange(*range) < NSMaxRange(rangeLimit)) 86 | { 87 | NSRange nextRange; 88 | CGFloat nextFontSize = [self fontAtIndex:NSMaxRange(*range) longestEffectiveRange:&nextRange inRange:rangeLimit].pointSize; 89 | if (fontSize != nextFontSize) break; 90 | (*range).length += nextRange.length; 91 | } 92 | 93 | return fontSize; 94 | } 95 | 96 | - (BOOL)boldAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 97 | { 98 | BOOL bold = [self fontAtIndex:index longestEffectiveRange:range inRange:rangeLimit].bold; 99 | 100 | while (NSMaxRange(*range) < NSMaxRange(rangeLimit)) 101 | { 102 | NSRange nextRange; 103 | CGFloat nextBold = [self fontAtIndex:NSMaxRange(*range) longestEffectiveRange:&nextRange inRange:rangeLimit].bold; 104 | if (bold != nextBold) break; 105 | (*range).length += nextRange.length; 106 | } 107 | 108 | return bold; 109 | } 110 | 111 | - (BOOL)italicAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 112 | { 113 | BOOL italic = [self fontAtIndex:index longestEffectiveRange:range inRange:rangeLimit].italic; 114 | 115 | while (NSMaxRange(*range) < NSMaxRange(rangeLimit)) 116 | { 117 | NSRange nextRange; 118 | CGFloat nextItalic = [self fontAtIndex:NSMaxRange(*range) longestEffectiveRange:&nextRange inRange:rangeLimit].italic; 119 | if (italic != nextItalic) break; 120 | (*range).length += nextRange.length; 121 | } 122 | 123 | return italic; 124 | } 125 | 126 | @end 127 | 128 | @implementation NSMutableAttributedString (Attributes) 129 | 130 | - (void)addFont:(UIFont *)font range:(NSRange)range 131 | { 132 | [self addAttribute:NSFontAttributeName value:font range:range]; 133 | } 134 | 135 | - (void)addFontName:(NSString *)fontName range:(NSRange)rangeLimit 136 | { 137 | fontName = [UIFont fontWithName:fontName size:[UIFont systemFontSize]].fontName; 138 | if (!fontName) return; 139 | 140 | NSRange range = NSMakeRange(rangeLimit.location, rangeLimit.length); 141 | UIFont *font = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 142 | 143 | if (![fontName isEqualToString:font.fontName]) 144 | [self addFont:[UIFont fontWithFont:font name:fontName] range:range]; 145 | 146 | while (NSMaxRange(range) < NSMaxRange(rangeLimit)) 147 | { 148 | range.location = NSMaxRange(range); 149 | range.length = rangeLimit.length - range.location; 150 | 151 | UIFont *nextFont = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 152 | if (![fontName isEqualToString:nextFont.fontName]) 153 | [self addFont:[UIFont fontWithFont:nextFont name:fontName] range:range]; 154 | } 155 | } 156 | 157 | - (void)addFontSize:(CGFloat)fontSize range:(NSRange)rangeLimit 158 | { 159 | if (!fontSize) return; 160 | 161 | NSRange range = NSMakeRange(rangeLimit.location, rangeLimit.length); 162 | UIFont *font = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 163 | 164 | if (fontSize != font.pointSize) 165 | [self addFont:[UIFont fontWithFont:font size:fontSize] range:range]; 166 | 167 | while (NSMaxRange(range) < NSMaxRange(rangeLimit)) 168 | { 169 | range.location = NSMaxRange(range); 170 | range.length = rangeLimit.length - range.location; 171 | 172 | UIFont *nextFont = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 173 | if (fontSize != nextFont.pointSize) 174 | [self addFont:[UIFont fontWithFont:nextFont size:fontSize] range:range]; 175 | } 176 | } 177 | 178 | - (void)addBold:(BOOL)bold range:(NSRange)rangeLimit 179 | { 180 | NSRange range = NSMakeRange(rangeLimit.location, rangeLimit.length); 181 | UIFont *font = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 182 | 183 | if (bold != font.bold) 184 | [self addFont:[UIFont fontWithFont:font bold:bold] range:range]; 185 | 186 | while (NSMaxRange(range) < NSMaxRange(rangeLimit)) 187 | { 188 | range.location = NSMaxRange(range); 189 | range.length = rangeLimit.length - range.location; 190 | 191 | UIFont *nextFont = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 192 | if (bold != nextFont.bold) 193 | [self addFont:[UIFont fontWithFont:nextFont bold:bold] range:range]; 194 | } 195 | } 196 | 197 | - (void)addItalic:(BOOL)italic range:(NSRange)rangeLimit 198 | { 199 | NSRange range = NSMakeRange(rangeLimit.location, rangeLimit.length); 200 | UIFont *font = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 201 | 202 | if (italic != font.italic) 203 | [self addFont:[UIFont fontWithFont:font italic:bold] range:range]; 204 | 205 | while (NSMaxRange(range) < NSMaxRange(rangeLimit)) 206 | { 207 | range.location = NSMaxRange(range); 208 | range.length = rangeLimit.length - range.location; 209 | 210 | UIFont *nextFont = [self fontAtIndex:range.location longestEffectiveRange:&range inRange:rangeLimit]; 211 | if (italic != nextFont.italic) 212 | [self addFont:[UIFont fontWithFont:nextFont italic:bold] range:range]; 213 | } 214 | } 215 | 216 | @end 217 | 218 | @implementation UIFont (Attributes) 219 | 220 | + (UIFont *)fontWithFont:(UIFont *)font size:(CGFloat)pointSize 221 | { 222 | return [self fontWithDescriptor:font.fontDescriptor size:pointSize]; 223 | } 224 | 225 | + (UIFont *)fontWithFont:(UIFont *)font name:(NSString *)fontName 226 | { 227 | //check if CTFontDescriptorRef and CTFontRef are leaking 228 | CTFontDescriptorRef attributes = CTFontDescriptorCreateWithNameAndSize((__bridge CFStringRef)fontName, 0.0f); 229 | return (__bridge UIFont *)CTFontCreateCopyWithAttributes((__bridge CTFontRef)font, 0.0f, NULL, attributes); 230 | } 231 | 232 | + (UIFont *)fontWithFont:(UIFont *)font bold:(BOOL)bold 233 | { 234 | //check if CTFontRef is leaking 235 | return (__bridge UIFont *)CTFontCreateCopyWithSymbolicTraits((__bridge CTFontRef)font, 0.0f, NULL, (bold?kCTFontBoldTrait:0), kCTFontBoldTrait); 236 | } 237 | 238 | + (UIFont *)fontWithFont:(UIFont *)font italic:(BOOL)italic 239 | { 240 | //check if CTFontRef is leaking 241 | return (__bridge UIFont *)CTFontCreateCopyWithSymbolicTraits((__bridge CTFontRef)font, 0.0f, NULL, (italic?kCTFontItalicTrait:0), kCTFontItalicTrait); 242 | } 243 | 244 | - (BOOL)bold 245 | { 246 | return (CTFontGetSymbolicTraits((__bridge CTFontRef)self) & kCTFontBoldTrait) != 0; 247 | } 248 | 249 | - (BOOL)italic 250 | { 251 | return (CTFontGetSymbolicTraits((__bridge CTFontRef)self) & kCTFontItalicTrait) != 0; 252 | } 253 | 254 | @end 255 | -------------------------------------------------------------------------------- /NSDate+Utilities/NSDate+Utilities.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "NSDate+Utilities.h" 4 | 5 | // Thanks, AshFurrow 6 | static const unsigned componentFlags = (NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit); 7 | 8 | @implementation NSDate (Utilities) 9 | 10 | // Courtesy of Lukasz Margielewski 11 | // Updated via Holger Haenisch 12 | + (NSCalendar *) currentCalendar 13 | { 14 | static NSCalendar *sharedCalendar = nil; 15 | if (!sharedCalendar) 16 | sharedCalendar = [NSCalendar autoupdatingCurrentCalendar]; 17 | return sharedCalendar; 18 | } 19 | 20 | #pragma mark - Relative Dates 21 | 22 | + (NSDate *) dateWithDaysFromNow: (NSInteger) days 23 | { 24 | // Thanks, Jim Morrison 25 | return [[NSDate date] dateByAddingDays:days]; 26 | } 27 | 28 | + (NSDate *) dateWithDaysBeforeNow: (NSInteger) days 29 | { 30 | // Thanks, Jim Morrison 31 | return [[NSDate date] dateBySubtractingDays:days]; 32 | } 33 | 34 | + (NSDate *) dateTomorrow 35 | { 36 | return [NSDate dateWithDaysFromNow:1]; 37 | } 38 | 39 | + (NSDate *) dateYesterday 40 | { 41 | return [NSDate dateWithDaysBeforeNow:1]; 42 | } 43 | 44 | + (NSDate *) dateWithHoursFromNow: (NSInteger) dHours 45 | { 46 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_HOUR * dHours; 47 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 48 | return newDate; 49 | } 50 | 51 | + (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours 52 | { 53 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_HOUR * dHours; 54 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 55 | return newDate; 56 | } 57 | 58 | + (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes 59 | { 60 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; 61 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 62 | return newDate; 63 | } 64 | 65 | + (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes 66 | { 67 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_MINUTE * dMinutes; 68 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 69 | return newDate; 70 | } 71 | 72 | #pragma mark - String Properties 73 | - (NSString *) stringWithFormat: (NSString *) format 74 | { 75 | NSDateFormatter *formatter = [NSDateFormatter new]; 76 | // formatter.locale = [NSLocale currentLocale]; // Necessary? 77 | formatter.dateFormat = format; 78 | return [formatter stringFromDate:self]; 79 | } 80 | 81 | - (NSString *) stringWithDateStyle: (NSDateFormatterStyle) dateStyle timeStyle: (NSDateFormatterStyle) timeStyle 82 | { 83 | NSDateFormatter *formatter = [NSDateFormatter new]; 84 | formatter.dateStyle = dateStyle; 85 | formatter.timeStyle = timeStyle; 86 | // formatter.locale = [NSLocale currentLocale]; // Necessary? 87 | return [formatter stringFromDate:self]; 88 | } 89 | 90 | - (NSString *) shortString 91 | { 92 | return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterShortStyle]; 93 | } 94 | 95 | - (NSString *) shortTimeString 96 | { 97 | return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterShortStyle]; 98 | } 99 | 100 | - (NSString *) shortDateString 101 | { 102 | return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterNoStyle]; 103 | } 104 | 105 | - (NSString *) mediumString 106 | { 107 | return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle ]; 108 | } 109 | 110 | - (NSString *) mediumTimeString 111 | { 112 | return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterMediumStyle ]; 113 | } 114 | 115 | - (NSString *) mediumDateString 116 | { 117 | return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle]; 118 | } 119 | 120 | - (NSString *) longString 121 | { 122 | return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterLongStyle ]; 123 | } 124 | 125 | - (NSString *) longTimeString 126 | { 127 | return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle ]; 128 | } 129 | 130 | - (NSString *) longDateString 131 | { 132 | return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterNoStyle]; 133 | } 134 | 135 | #pragma mark - Comparing Dates 136 | 137 | - (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate 138 | { 139 | NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 140 | NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags fromDate:aDate]; 141 | return ((components1.year == components2.year) && 142 | (components1.month == components2.month) && 143 | (components1.day == components2.day)); 144 | } 145 | 146 | - (BOOL) isToday 147 | { 148 | return [self isEqualToDateIgnoringTime:[NSDate date]]; 149 | } 150 | 151 | - (BOOL) isTomorrow 152 | { 153 | return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]]; 154 | } 155 | 156 | - (BOOL) isYesterday 157 | { 158 | return [self isEqualToDateIgnoringTime:[NSDate dateYesterday]]; 159 | } 160 | 161 | - (BOOL)isTheDayAfterTomorrow 162 | { 163 | return [self isEqualToDateIgnoringTime:[NSDate dateWithDaysFromNow:2]]; 164 | } 165 | 166 | // This hard codes the assumption that a week is 7 days 167 | - (BOOL) isSameWeekAsDate: (NSDate *) aDate 168 | { 169 | NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 170 | NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags fromDate:aDate]; 171 | 172 | // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week 173 | if (components1.week != components2.week) return NO; 174 | 175 | // Must have a time interval under 1 week. Thanks @aclark 176 | return (abs([self timeIntervalSinceDate:aDate]) < D_WEEK); 177 | } 178 | 179 | - (BOOL) isThisWeek 180 | { 181 | return [self isSameWeekAsDate:[NSDate date]]; 182 | } 183 | 184 | - (BOOL) isNextWeek 185 | { 186 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_WEEK; 187 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 188 | return [self isSameWeekAsDate:newDate]; 189 | } 190 | 191 | - (BOOL) isLastWeek 192 | { 193 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_WEEK; 194 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 195 | return [self isSameWeekAsDate:newDate]; 196 | } 197 | 198 | // Thanks, mspasov 199 | - (BOOL) isSameMonthAsDate: (NSDate *) aDate 200 | { 201 | NSDateComponents *components1 = [[NSDate currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:self]; 202 | NSDateComponents *components2 = [[NSDate currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:aDate]; 203 | return ((components1.month == components2.month) && 204 | (components1.year == components2.year)); 205 | } 206 | 207 | - (BOOL) isThisMonth 208 | { 209 | return [self isSameMonthAsDate:[NSDate date]]; 210 | } 211 | 212 | // Thanks Marcin Krzyzanowski, also for adding/subtracting years and months 213 | - (BOOL) isLastMonth 214 | { 215 | return [self isSameMonthAsDate:[[NSDate date] dateBySubtractingMonths:1]]; 216 | } 217 | 218 | - (BOOL) isNextMonth 219 | { 220 | return [self isSameMonthAsDate:[[NSDate date] dateByAddingMonths:1]]; 221 | } 222 | 223 | - (BOOL) isSameYearAsDate: (NSDate *) aDate 224 | { 225 | NSDateComponents *components1 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:self]; 226 | NSDateComponents *components2 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:aDate]; 227 | return (components1.year == components2.year); 228 | } 229 | 230 | - (BOOL) isThisYear 231 | { 232 | // Thanks, baspellis 233 | return [self isSameYearAsDate:[NSDate date]]; 234 | } 235 | 236 | - (BOOL) isNextYear 237 | { 238 | NSDateComponents *components1 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:self]; 239 | NSDateComponents *components2 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:[NSDate date]]; 240 | 241 | return (components1.year == (components2.year + 1)); 242 | } 243 | 244 | - (BOOL) isLastYear 245 | { 246 | NSDateComponents *components1 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:self]; 247 | NSDateComponents *components2 = [[NSDate currentCalendar] components:NSYearCalendarUnit fromDate:[NSDate date]]; 248 | 249 | return (components1.year == (components2.year - 1)); 250 | } 251 | 252 | - (BOOL) isEarlierThanDate: (NSDate *) aDate 253 | { 254 | return ([self compare:aDate] == NSOrderedAscending); 255 | } 256 | 257 | - (BOOL) isLaterThanDate: (NSDate *) aDate 258 | { 259 | return ([self compare:aDate] == NSOrderedDescending); 260 | } 261 | 262 | // Thanks, markrickert 263 | - (BOOL) isInFuture 264 | { 265 | return ([self isLaterThanDate:[NSDate date]]); 266 | } 267 | 268 | // Thanks, markrickert 269 | - (BOOL) isInPast 270 | { 271 | return ([self isEarlierThanDate:[NSDate date]]); 272 | } 273 | 274 | 275 | #pragma mark - Roles 276 | - (BOOL) isTypicallyWeekend 277 | { 278 | NSDateComponents *components = [[NSDate currentCalendar] components:NSWeekdayCalendarUnit fromDate:self]; 279 | if ((components.weekday == 1) || 280 | (components.weekday == 7)) 281 | return YES; 282 | return NO; 283 | } 284 | 285 | - (BOOL) isTypicallyWorkday 286 | { 287 | return ![self isTypicallyWeekend]; 288 | } 289 | 290 | #pragma mark - Adjusting Dates 291 | 292 | // Thaks, rsjohnson 293 | - (NSDate *) dateByAddingYears: (NSInteger) dYears 294 | { 295 | NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; 296 | [dateComponents setYear:dYears]; 297 | NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; 298 | return newDate; 299 | } 300 | 301 | - (NSDate *) dateBySubtractingYears: (NSInteger) dYears 302 | { 303 | return [self dateByAddingYears:-dYears]; 304 | } 305 | 306 | - (NSDate *) dateByAddingMonths: (NSInteger) dMonths 307 | { 308 | NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; 309 | [dateComponents setMonth:dMonths]; 310 | NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; 311 | return newDate; 312 | } 313 | 314 | - (NSDate *) dateBySubtractingMonths: (NSInteger) dMonths 315 | { 316 | return [self dateByAddingMonths:-dMonths]; 317 | } 318 | 319 | // Courtesy of dedan who mentions issues with Daylight Savings 320 | - (NSDate *) dateByAddingDays: (NSInteger) dDays 321 | { 322 | NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; 323 | [dateComponents setDay:dDays]; 324 | NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; 325 | return newDate; 326 | } 327 | 328 | - (NSDate *) dateBySubtractingDays: (NSInteger) dDays 329 | { 330 | return [self dateByAddingDays: (dDays * -1)]; 331 | } 332 | 333 | - (NSDate *) dateByAddingHours: (NSInteger) dHours 334 | { 335 | NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_HOUR * dHours; 336 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 337 | return newDate; 338 | } 339 | 340 | - (NSDate *) dateBySubtractingHours: (NSInteger) dHours 341 | { 342 | return [self dateByAddingHours: (dHours * -1)]; 343 | } 344 | 345 | - (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes 346 | { 347 | NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; 348 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 349 | return newDate; 350 | } 351 | 352 | - (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes 353 | { 354 | return [self dateByAddingMinutes: (dMinutes * -1)]; 355 | } 356 | 357 | - (NSDateComponents *) componentsWithOffsetFromDate: (NSDate *) aDate 358 | { 359 | NSDateComponents *dTime = [[NSDate currentCalendar] components:componentFlags fromDate:aDate toDate:self options:0]; 360 | return dTime; 361 | } 362 | 363 | #pragma mark - Extremes 364 | 365 | - (NSDate *) dateAtStartOfDay 366 | { 367 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 368 | components.hour = 0; 369 | components.minute = 0; 370 | components.second = 0; 371 | return [[NSDate currentCalendar] dateFromComponents:components]; 372 | } 373 | 374 | // Thanks gsempe & mteece 375 | - (NSDate *) dateAtEndOfDay 376 | { 377 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 378 | components.hour = 23; // Thanks Aleksey Kononov 379 | components.minute = 59; 380 | components.second = 59; 381 | return [[NSDate currentCalendar] dateFromComponents:components]; 382 | } 383 | 384 | #pragma mark - Retrieving Intervals 385 | 386 | - (NSInteger) minutesAfterDate: (NSDate *) aDate 387 | { 388 | NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; 389 | return (NSInteger) (ti / D_MINUTE); 390 | } 391 | 392 | - (NSInteger) minutesBeforeDate: (NSDate *) aDate 393 | { 394 | NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; 395 | return (NSInteger) (ti / D_MINUTE); 396 | } 397 | 398 | - (NSInteger) hoursAfterDate: (NSDate *) aDate 399 | { 400 | NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; 401 | return (NSInteger) (ti / D_HOUR); 402 | } 403 | 404 | - (NSInteger) hoursBeforeDate: (NSDate *) aDate 405 | { 406 | NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; 407 | return (NSInteger) (ti / D_HOUR); 408 | } 409 | 410 | - (NSInteger) daysAfterDate: (NSDate *) aDate 411 | { 412 | NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; 413 | return (NSInteger) (ti / D_DAY); 414 | } 415 | 416 | - (NSInteger) daysBeforeDate: (NSDate *) aDate 417 | { 418 | NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; 419 | return (NSInteger) (ti / D_DAY); 420 | } 421 | 422 | // Thanks, dmitrydims 423 | // I have not yet thoroughly tested this 424 | - (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate 425 | { 426 | NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 427 | NSDateComponents *components = [gregorianCalendar components:NSDayCalendarUnit fromDate:self toDate:anotherDate options:0]; 428 | return components.day; 429 | } 430 | 431 | #pragma mark - Decomposing Dates 432 | 433 | - (NSInteger) nearestHour 434 | { 435 | NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30; 436 | NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; 437 | NSDateComponents *components = [[NSDate currentCalendar] components:NSHourCalendarUnit fromDate:newDate]; 438 | return components.hour; 439 | } 440 | 441 | - (NSInteger) hour 442 | { 443 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 444 | return components.hour; 445 | } 446 | 447 | - (NSInteger) minute 448 | { 449 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 450 | return components.minute; 451 | } 452 | 453 | - (NSInteger) seconds 454 | { 455 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 456 | return components.second; 457 | } 458 | 459 | - (NSInteger) day 460 | { 461 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 462 | return components.day; 463 | } 464 | 465 | - (NSInteger) month 466 | { 467 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 468 | return components.month; 469 | } 470 | 471 | - (NSInteger) week 472 | { 473 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 474 | return components.week; 475 | } 476 | 477 | - (NSInteger) weekday 478 | { 479 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 480 | return components.weekday; 481 | } 482 | 483 | - (NSInteger) nthWeekday // e.g. 2nd Tuesday of the month is 2 484 | { 485 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 486 | return components.weekdayOrdinal; 487 | } 488 | 489 | - (NSInteger) year 490 | { 491 | NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; 492 | return components.year; 493 | } 494 | @end -------------------------------------------------------------------------------- /EXTScope/metamacros.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Macros for metaprogramming 3 | * ExtendedC 4 | * 5 | * Copyright (C) 2012 Justin Spahr-Summers 6 | * Released under the MIT license 7 | */ 8 | 9 | #ifndef EXTC_METAMACROS_H 10 | #define EXTC_METAMACROS_H 11 | 12 | 13 | /** 14 | * Executes one or more expressions (which may have a void type, such as a call 15 | * to a function that returns no value) and always returns true. 16 | */ 17 | #define metamacro_exprify(...) \ 18 | ((__VA_ARGS__), true) 19 | 20 | /** 21 | * Returns a string representation of VALUE after full macro expansion. 22 | */ 23 | #define metamacro_stringify(VALUE) \ 24 | metamacro_stringify_(VALUE) 25 | 26 | /** 27 | * Returns A and B concatenated after full macro expansion. 28 | */ 29 | #define metamacro_concat(A, B) \ 30 | metamacro_concat_(A, B) 31 | 32 | /** 33 | * Returns the Nth variadic argument (starting from zero). At least 34 | * N + 1 variadic arguments must be given. N must be between zero and twenty, 35 | * inclusive. 36 | */ 37 | #define metamacro_at(N, ...) \ 38 | metamacro_concat(metamacro_at, N)(__VA_ARGS__) 39 | 40 | /** 41 | * Returns the number of arguments (up to twenty) provided to the macro. At 42 | * least one argument must be provided. 43 | * 44 | * Inspired by P99: http://p99.gforge.inria.fr 45 | */ 46 | #define metamacro_argcount(...) \ 47 | metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 48 | 49 | /** 50 | * Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is 51 | * given. Only the index and current argument will thus be passed to MACRO. 52 | */ 53 | #define metamacro_foreach(MACRO, SEP, ...) \ 54 | metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) 55 | 56 | /** 57 | * For each consecutive variadic argument (up to twenty), MACRO is passed the 58 | * zero-based index of the current argument, CONTEXT, and then the argument 59 | * itself. The results of adjoining invocations of MACRO are then separated by 60 | * SEP. 61 | * 62 | * Inspired by P99: http://p99.gforge.inria.fr 63 | */ 64 | #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ 65 | metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) 66 | 67 | /** 68 | * Identical to #metamacro_foreach_cxt. This can be used when the former would 69 | * fail due to recursive macro expansion. 70 | */ 71 | #define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ 72 | metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) 73 | 74 | /** 75 | * In consecutive order, appends each variadic argument (up to twenty) onto 76 | * BASE. The resulting concatenations are then separated by SEP. 77 | * 78 | * This is primarily useful to manipulate a list of macro invocations into instead 79 | * invoking a different, possibly related macro. 80 | */ 81 | #define metamacro_foreach_concat(BASE, SEP, ...) \ 82 | metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) 83 | 84 | /** 85 | * Iterates COUNT times, each time invoking MACRO with the current index 86 | * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO 87 | * are then separated by SEP. 88 | * 89 | * COUNT must be an integer between zero and twenty, inclusive. 90 | */ 91 | #define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ 92 | metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT) 93 | 94 | /** 95 | * Returns the first argument given. At least one argument must be provided. 96 | * 97 | * This is useful when implementing a variadic macro, where you may have only 98 | * one variadic argument, but no way to retrieve it (for example, because \c ... 99 | * always needs to match at least one argument). 100 | * 101 | * @code 102 | 103 | #define varmacro(...) \ 104 | metamacro_head(__VA_ARGS__) 105 | 106 | * @endcode 107 | */ 108 | #define metamacro_head(...) \ 109 | metamacro_head_(__VA_ARGS__, 0) 110 | 111 | /** 112 | * Returns every argument except the first. At least two arguments must be 113 | * provided. 114 | */ 115 | #define metamacro_tail(...) \ 116 | metamacro_tail_(__VA_ARGS__) 117 | 118 | /** 119 | * Returns the first N (up to twenty) variadic arguments as a new argument list. 120 | * At least N variadic arguments must be provided. 121 | */ 122 | #define metamacro_take(N, ...) \ 123 | metamacro_concat(metamacro_take, N)(__VA_ARGS__) 124 | 125 | /** 126 | * Removes the first N (up to twenty) variadic arguments from the given argument 127 | * list. At least N variadic arguments must be provided. 128 | */ 129 | #define metamacro_drop(N, ...) \ 130 | metamacro_concat(metamacro_drop, N)(__VA_ARGS__) 131 | 132 | /** 133 | * Decrements VAL, which must be a number between zero and twenty, inclusive. 134 | * 135 | * This is primarily useful when dealing with indexes and counts in 136 | * metaprogramming. 137 | */ 138 | #define metamacro_dec(VAL) \ 139 | metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) 140 | 141 | /** 142 | * Increments VAL, which must be a number between zero and twenty, inclusive. 143 | * 144 | * This is primarily useful when dealing with indexes and counts in 145 | * metaprogramming. 146 | */ 147 | #define metamacro_inc(VAL) \ 148 | metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) 149 | 150 | /** 151 | * If A is equal to B, the next argument list is expanded; otherwise, the 152 | * argument list after that is expanded. A and B must be numbers between zero 153 | * and twenty, inclusive. Additionally, B must be greater than or equal to A. 154 | * 155 | * @code 156 | 157 | // expands to true 158 | metamacro_if_eq(0, 0)(true)(false) 159 | 160 | // expands to false 161 | metamacro_if_eq(0, 1)(true)(false) 162 | 163 | * @endcode 164 | * 165 | * This is primarily useful when dealing with indexes and counts in 166 | * metaprogramming. 167 | */ 168 | #define metamacro_if_eq(A, B) \ 169 | metamacro_concat(metamacro_if_eq, A)(B) 170 | 171 | /** 172 | * Identical to #metamacro_if_eq. This can be used when the former would fail 173 | * due to recursive macro expansion. 174 | */ 175 | #define metamacro_if_eq_recursive(A, B) \ 176 | metamacro_concat(metamacro_if_eq_recursive, A)(B) 177 | 178 | /** 179 | * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and 180 | * twenty, inclusive. 181 | * 182 | * For the purposes of this test, zero is considered even. 183 | */ 184 | #define metamacro_is_even(N) \ 185 | metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) 186 | 187 | /** 188 | * Returns the logical NOT of B, which must be the number zero or one. 189 | */ 190 | #define metamacro_not(B) \ 191 | metamacro_at(B, 1, 0) 192 | 193 | // IMPLEMENTATION DETAILS FOLLOW! 194 | // Do not write code that depends on anything below this line. 195 | #define metamacro_stringify_(VALUE) # VALUE 196 | #define metamacro_concat_(A, B) A ## B 197 | #define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG) 198 | #define metamacro_head_(FIRST, ...) FIRST 199 | #define metamacro_tail_(FIRST, ...) __VA_ARGS__ 200 | #define metamacro_consume_(...) 201 | #define metamacro_expand_(...) __VA_ARGS__ 202 | 203 | // implemented from scratch so that metamacro_concat() doesn't end up nesting 204 | #define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG) 205 | #define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG 206 | 207 | // metamacro_at expansions 208 | #define metamacro_at0(...) metamacro_head(__VA_ARGS__) 209 | #define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__) 210 | #define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__) 211 | #define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__) 212 | #define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__) 213 | #define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__) 214 | #define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__) 215 | #define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__) 216 | #define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__) 217 | #define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__) 218 | #define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__) 219 | #define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__) 220 | #define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__) 221 | #define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__) 222 | #define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__) 223 | #define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__) 224 | #define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__) 225 | #define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__) 226 | #define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__) 227 | #define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__) 228 | #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__) 229 | 230 | // metamacro_foreach_cxt expansions 231 | #define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT) 232 | #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) 233 | 234 | #define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ 235 | metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ 236 | SEP \ 237 | MACRO(1, CONTEXT, _1) 238 | 239 | #define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 240 | metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ 241 | SEP \ 242 | MACRO(2, CONTEXT, _2) 243 | 244 | #define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 245 | metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 246 | SEP \ 247 | MACRO(3, CONTEXT, _3) 248 | 249 | #define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 250 | metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 251 | SEP \ 252 | MACRO(4, CONTEXT, _4) 253 | 254 | #define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 255 | metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 256 | SEP \ 257 | MACRO(5, CONTEXT, _5) 258 | 259 | #define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 260 | metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 261 | SEP \ 262 | MACRO(6, CONTEXT, _6) 263 | 264 | #define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 265 | metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 266 | SEP \ 267 | MACRO(7, CONTEXT, _7) 268 | 269 | #define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 270 | metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 271 | SEP \ 272 | MACRO(8, CONTEXT, _8) 273 | 274 | #define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 275 | metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 276 | SEP \ 277 | MACRO(9, CONTEXT, _9) 278 | 279 | #define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 280 | metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 281 | SEP \ 282 | MACRO(10, CONTEXT, _10) 283 | 284 | #define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 285 | metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 286 | SEP \ 287 | MACRO(11, CONTEXT, _11) 288 | 289 | #define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 290 | metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 291 | SEP \ 292 | MACRO(12, CONTEXT, _12) 293 | 294 | #define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 295 | metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 296 | SEP \ 297 | MACRO(13, CONTEXT, _13) 298 | 299 | #define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 300 | metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 301 | SEP \ 302 | MACRO(14, CONTEXT, _14) 303 | 304 | #define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 305 | metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 306 | SEP \ 307 | MACRO(15, CONTEXT, _15) 308 | 309 | #define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 310 | metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 311 | SEP \ 312 | MACRO(16, CONTEXT, _16) 313 | 314 | #define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 315 | metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 316 | SEP \ 317 | MACRO(17, CONTEXT, _17) 318 | 319 | #define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 320 | metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 321 | SEP \ 322 | MACRO(18, CONTEXT, _18) 323 | 324 | #define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ 325 | metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 326 | SEP \ 327 | MACRO(19, CONTEXT, _19) 328 | 329 | // metamacro_foreach_cxt_recursive expansions 330 | #define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT) 331 | #define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) 332 | 333 | #define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ 334 | metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ 335 | SEP \ 336 | MACRO(1, CONTEXT, _1) 337 | 338 | #define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 339 | metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ 340 | SEP \ 341 | MACRO(2, CONTEXT, _2) 342 | 343 | #define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 344 | metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 345 | SEP \ 346 | MACRO(3, CONTEXT, _3) 347 | 348 | #define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 349 | metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 350 | SEP \ 351 | MACRO(4, CONTEXT, _4) 352 | 353 | #define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 354 | metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 355 | SEP \ 356 | MACRO(5, CONTEXT, _5) 357 | 358 | #define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 359 | metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 360 | SEP \ 361 | MACRO(6, CONTEXT, _6) 362 | 363 | #define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 364 | metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 365 | SEP \ 366 | MACRO(7, CONTEXT, _7) 367 | 368 | #define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 369 | metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 370 | SEP \ 371 | MACRO(8, CONTEXT, _8) 372 | 373 | #define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 374 | metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 375 | SEP \ 376 | MACRO(9, CONTEXT, _9) 377 | 378 | #define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 379 | metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 380 | SEP \ 381 | MACRO(10, CONTEXT, _10) 382 | 383 | #define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 384 | metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 385 | SEP \ 386 | MACRO(11, CONTEXT, _11) 387 | 388 | #define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 389 | metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 390 | SEP \ 391 | MACRO(12, CONTEXT, _12) 392 | 393 | #define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 394 | metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 395 | SEP \ 396 | MACRO(13, CONTEXT, _13) 397 | 398 | #define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 399 | metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 400 | SEP \ 401 | MACRO(14, CONTEXT, _14) 402 | 403 | #define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 404 | metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 405 | SEP \ 406 | MACRO(15, CONTEXT, _15) 407 | 408 | #define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 409 | metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 410 | SEP \ 411 | MACRO(16, CONTEXT, _16) 412 | 413 | #define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 414 | metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 415 | SEP \ 416 | MACRO(17, CONTEXT, _17) 417 | 418 | #define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 419 | metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 420 | SEP \ 421 | MACRO(18, CONTEXT, _18) 422 | 423 | #define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ 424 | metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 425 | SEP \ 426 | MACRO(19, CONTEXT, _19) 427 | 428 | // metamacro_for_cxt expansions 429 | #define metamacro_for_cxt0(MACRO, SEP, CONTEXT) 430 | #define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) 431 | 432 | #define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ 433 | metamacro_for_cxt1(MACRO, SEP, CONTEXT) \ 434 | SEP \ 435 | MACRO(1, CONTEXT) 436 | 437 | #define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ 438 | metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ 439 | SEP \ 440 | MACRO(2, CONTEXT) 441 | 442 | #define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ 443 | metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ 444 | SEP \ 445 | MACRO(3, CONTEXT) 446 | 447 | #define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ 448 | metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ 449 | SEP \ 450 | MACRO(4, CONTEXT) 451 | 452 | #define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ 453 | metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ 454 | SEP \ 455 | MACRO(5, CONTEXT) 456 | 457 | #define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ 458 | metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ 459 | SEP \ 460 | MACRO(6, CONTEXT) 461 | 462 | #define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ 463 | metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ 464 | SEP \ 465 | MACRO(7, CONTEXT) 466 | 467 | #define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ 468 | metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ 469 | SEP \ 470 | MACRO(8, CONTEXT) 471 | 472 | #define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ 473 | metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ 474 | SEP \ 475 | MACRO(9, CONTEXT) 476 | 477 | #define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ 478 | metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ 479 | SEP \ 480 | MACRO(10, CONTEXT) 481 | 482 | #define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ 483 | metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ 484 | SEP \ 485 | MACRO(11, CONTEXT) 486 | 487 | #define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ 488 | metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ 489 | SEP \ 490 | MACRO(12, CONTEXT) 491 | 492 | #define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ 493 | metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ 494 | SEP \ 495 | MACRO(13, CONTEXT) 496 | 497 | #define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ 498 | metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ 499 | SEP \ 500 | MACRO(14, CONTEXT) 501 | 502 | #define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ 503 | metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ 504 | SEP \ 505 | MACRO(15, CONTEXT) 506 | 507 | #define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ 508 | metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ 509 | SEP \ 510 | MACRO(16, CONTEXT) 511 | 512 | #define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ 513 | metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ 514 | SEP \ 515 | MACRO(17, CONTEXT) 516 | 517 | #define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ 518 | metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ 519 | SEP \ 520 | MACRO(18, CONTEXT) 521 | 522 | #define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ 523 | metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ 524 | SEP \ 525 | MACRO(19, CONTEXT) 526 | 527 | // metamacro_if_eq expansions 528 | #define metamacro_if_eq0(VALUE) \ 529 | metamacro_concat(metamacro_if_eq0_, VALUE) 530 | 531 | #define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_ 532 | #define metamacro_if_eq0_1(...) metamacro_expand_ 533 | #define metamacro_if_eq0_2(...) metamacro_expand_ 534 | #define metamacro_if_eq0_3(...) metamacro_expand_ 535 | #define metamacro_if_eq0_4(...) metamacro_expand_ 536 | #define metamacro_if_eq0_5(...) metamacro_expand_ 537 | #define metamacro_if_eq0_6(...) metamacro_expand_ 538 | #define metamacro_if_eq0_7(...) metamacro_expand_ 539 | #define metamacro_if_eq0_8(...) metamacro_expand_ 540 | #define metamacro_if_eq0_9(...) metamacro_expand_ 541 | #define metamacro_if_eq0_10(...) metamacro_expand_ 542 | #define metamacro_if_eq0_11(...) metamacro_expand_ 543 | #define metamacro_if_eq0_12(...) metamacro_expand_ 544 | #define metamacro_if_eq0_13(...) metamacro_expand_ 545 | #define metamacro_if_eq0_14(...) metamacro_expand_ 546 | #define metamacro_if_eq0_15(...) metamacro_expand_ 547 | #define metamacro_if_eq0_16(...) metamacro_expand_ 548 | #define metamacro_if_eq0_17(...) metamacro_expand_ 549 | #define metamacro_if_eq0_18(...) metamacro_expand_ 550 | #define metamacro_if_eq0_19(...) metamacro_expand_ 551 | #define metamacro_if_eq0_20(...) metamacro_expand_ 552 | 553 | #define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE)) 554 | #define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE)) 555 | #define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE)) 556 | #define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE)) 557 | #define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE)) 558 | #define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE)) 559 | #define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE)) 560 | #define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE)) 561 | #define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE)) 562 | #define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE)) 563 | #define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE)) 564 | #define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE)) 565 | #define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE)) 566 | #define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE)) 567 | #define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE)) 568 | #define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE)) 569 | #define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE)) 570 | #define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE)) 571 | #define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE)) 572 | #define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE)) 573 | 574 | // metamacro_if_eq_recursive expansions 575 | #define metamacro_if_eq_recursive0(VALUE) \ 576 | metamacro_concat(metamacro_if_eq_recursive0_, VALUE) 577 | 578 | #define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_ 579 | #define metamacro_if_eq_recursive0_1(...) metamacro_expand_ 580 | #define metamacro_if_eq_recursive0_2(...) metamacro_expand_ 581 | #define metamacro_if_eq_recursive0_3(...) metamacro_expand_ 582 | #define metamacro_if_eq_recursive0_4(...) metamacro_expand_ 583 | #define metamacro_if_eq_recursive0_5(...) metamacro_expand_ 584 | #define metamacro_if_eq_recursive0_6(...) metamacro_expand_ 585 | #define metamacro_if_eq_recursive0_7(...) metamacro_expand_ 586 | #define metamacro_if_eq_recursive0_8(...) metamacro_expand_ 587 | #define metamacro_if_eq_recursive0_9(...) metamacro_expand_ 588 | #define metamacro_if_eq_recursive0_10(...) metamacro_expand_ 589 | #define metamacro_if_eq_recursive0_11(...) metamacro_expand_ 590 | #define metamacro_if_eq_recursive0_12(...) metamacro_expand_ 591 | #define metamacro_if_eq_recursive0_13(...) metamacro_expand_ 592 | #define metamacro_if_eq_recursive0_14(...) metamacro_expand_ 593 | #define metamacro_if_eq_recursive0_15(...) metamacro_expand_ 594 | #define metamacro_if_eq_recursive0_16(...) metamacro_expand_ 595 | #define metamacro_if_eq_recursive0_17(...) metamacro_expand_ 596 | #define metamacro_if_eq_recursive0_18(...) metamacro_expand_ 597 | #define metamacro_if_eq_recursive0_19(...) metamacro_expand_ 598 | #define metamacro_if_eq_recursive0_20(...) metamacro_expand_ 599 | 600 | #define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE)) 601 | #define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE)) 602 | #define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE)) 603 | #define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE)) 604 | #define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE)) 605 | #define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE)) 606 | #define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE)) 607 | #define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE)) 608 | #define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE)) 609 | #define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE)) 610 | #define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE)) 611 | #define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE)) 612 | #define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE)) 613 | #define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE)) 614 | #define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE)) 615 | #define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE)) 616 | #define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE)) 617 | #define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE)) 618 | #define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE)) 619 | #define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE)) 620 | 621 | // metamacro_take expansions 622 | #define metamacro_take0(...) 623 | #define metamacro_take1(...) metamacro_head(__VA_ARGS__) 624 | #define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__)) 625 | #define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__)) 626 | #define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__)) 627 | #define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__)) 628 | #define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__)) 629 | #define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__)) 630 | #define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__)) 631 | #define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__)) 632 | #define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__)) 633 | #define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__)) 634 | #define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__)) 635 | #define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__)) 636 | #define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__)) 637 | #define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__)) 638 | #define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__)) 639 | #define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__)) 640 | #define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__)) 641 | #define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__)) 642 | #define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__)) 643 | 644 | // metamacro_drop expansions 645 | #define metamacro_drop0(...) __VA_ARGS__ 646 | #define metamacro_drop1(...) metamacro_tail(__VA_ARGS__) 647 | #define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__)) 648 | #define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__)) 649 | #define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__)) 650 | #define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__)) 651 | #define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__)) 652 | #define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__)) 653 | #define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__)) 654 | #define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__)) 655 | #define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__)) 656 | #define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__)) 657 | #define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__)) 658 | #define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__)) 659 | #define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__)) 660 | #define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__)) 661 | #define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__)) 662 | #define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__)) 663 | #define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__)) 664 | #define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) 665 | #define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) 666 | 667 | #endif 668 | --------------------------------------------------------------------------------