Skip to content

Instantly share code, notes, and snippets.

@psobko
Created September 16, 2015 20:36
Show Gist options
  • Save psobko/7ff9da838b981a97d7b5 to your computer and use it in GitHub Desktop.
Save psobko/7ff9da838b981a97d7b5 to your computer and use it in GitHub Desktop.
DLogVars() - Log up to 28 expressions in DLog format
//
// Logger.h
// Logger
//
// Created by psobko on 9/16/15.
// Copyright (c) 2015 psobko. All rights reserved.
//
#ifndef Logger_Logger_h
#define Logger_Logger_h
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 0
#endif
#if DEBUG
#define DLog(fmt, ...) if(DEBUG_LEVEL) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogVars(...) if(DEBUG_LEVEL) DLog(@"Printing Variables");CALL_MACRO_X_FOR_EACH(LOG_EXPR, ##__VA_ARGS__)
#else
#define DLog(...)
#endif
//Expression Logging
//Copyright (c) 2008-2010, Vincent Gable.
//http://vincentgable.com
//based off http://www.dribin.org/dave/blog/archives/2008/09/22/convert_to_nsstring/
static BOOL TypeCodeIsCharArray(const char *typeCode){
size_t len = strlen(typeCode);
if(len <= 2)
return NO;
size_t lastCharOffset = len - 1;
size_t secondToLastCharOffset = lastCharOffset - 1 ;
BOOL isCharArray = typeCode[0] == '[' &&
typeCode[secondToLastCharOffset] == 'c' && typeCode[lastCharOffset] == ']';
for(int i = 1; i < secondToLastCharOffset; i++)
isCharArray = isCharArray && isdigit(typeCode[i]);
return isCharArray;
}
//since BOOL is #defined as a signed char, we treat the value as
//a BOOL if it is exactly YES or NO, and a char otherwise.
static NSString* VTPGStringFromBoolOrCharValue(BOOL boolOrCharvalue) {
if(boolOrCharvalue == YES)
return @"YES";
if(boolOrCharvalue == NO)
return @"NO";
return [NSString stringWithFormat:@"'%c'", boolOrCharvalue];
}
static NSString *VTPGStringFromFourCharCodeOrUnsignedInt32(FourCharCode fourcc) {
return [NSString stringWithFormat:@"%u ('%c%c%c%c')",
fourcc,
(fourcc >> 24) & 0xFF,
(fourcc >> 16) & 0xFF,
(fourcc >> 8) & 0xFF,
fourcc & 0xFF];
}
static NSString *StringFromNSDecimalWithCurrentLocal(NSDecimal dcm) {
return NSDecimalString(&dcm, [NSLocale currentLocale]);
}
NSString * VTPG_DDToStringFromTypeAndValue(const char * typeCode, void * value) {
#define IF_TYPE_MATCHES_INTERPRET_WITH(typeToMatch,func) \
if (strcmp(typeCode, @encode(typeToMatch)) == 0) \
return (func)(*(typeToMatch*)value)
#if TARGET_OS_IPHONE
IF_TYPE_MATCHES_INTERPRET_WITH(CGPoint,NSStringFromCGPoint);
IF_TYPE_MATCHES_INTERPRET_WITH(CGSize,NSStringFromCGSize);
IF_TYPE_MATCHES_INTERPRET_WITH(CGRect,NSStringFromCGRect);
#else
IF_TYPE_MATCHES_INTERPRET_WITH(NSPoint,NSStringFromPoint);
IF_TYPE_MATCHES_INTERPRET_WITH(NSSize,NSStringFromSize);
IF_TYPE_MATCHES_INTERPRET_WITH(NSRect,NSStringFromRect);
#endif
IF_TYPE_MATCHES_INTERPRET_WITH(NSRange,NSStringFromRange);
IF_TYPE_MATCHES_INTERPRET_WITH(Class,NSStringFromClass);
IF_TYPE_MATCHES_INTERPRET_WITH(SEL,NSStringFromSelector);
IF_TYPE_MATCHES_INTERPRET_WITH(BOOL,VTPGStringFromBoolOrCharValue);
IF_TYPE_MATCHES_INTERPRET_WITH(NSDecimal,StringFromNSDecimalWithCurrentLocal);
#define IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(typeToMatch,formatString) \
if (strcmp(typeCode, @encode(typeToMatch)) == 0) \
return [NSString stringWithFormat:(formatString), (*(typeToMatch*)value)]
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(CFStringRef,@"%@"); //CFStringRef is toll-free bridged to NSString*
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(CFArrayRef,@"%@"); //CFArrayRef is toll-free bridged to NSArray*
IF_TYPE_MATCHES_INTERPRET_WITH(FourCharCode, VTPGStringFromFourCharCodeOrUnsignedInt32);
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(long long,@"%lld");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(unsigned long long,@"%llu");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(float,@"%f");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(double,@"%f");
#if __has_feature(objc_arc)
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(__unsafe_unretained id,@"%@");
#else /* not __has_feature(objc_arc) */
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(id,@"%@");
#endif
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(short,@"%hi");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(unsigned short,@"%hu");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(int,@"%i");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(unsigned, @"%u");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(long,@"%li");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(long double,@"%Lf"); //WARNING on older versions of OS X, @encode(long double) == @encode(double)
//C-strings
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(char*, @"%s");
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(const char*, @"%s");
if(TypeCodeIsCharArray(typeCode))
return [NSString stringWithFormat:@"%s", (char*)value];
IF_TYPE_MATCHES_INTERPRET_WITH_FORMAT(void*,@"(void*)%p");
//This is a hack to print out CLLocationCoordinate2D, without needing to #import <CoreLocation/CoreLocation.h>
//A CLLocationCoordinate2D is a struct made up of 2 doubles.
//We detect it by hard-coding the result of @encode(CLLocationCoordinate2D).
//We get at the fields by treating it like an array of doubles, which it is identical to in memory.
if(strcmp(typeCode, "{?=dd}")==0)//@encode(CLLocationCoordinate2D)
return [NSString stringWithFormat:@"{latitude=%g,longitude=%g}",((double*)value)[0],((double*)value)[1]];
//we don't know how to convert this typecode into an NSString
return nil;
}
//Variadic ForEach Macro
#define _GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, N, ...) N
#define _fe_0(_call, ...)
#define _fe_1(_call, x) _call(x)
#define _fe_2(_call, x, ...) _call(x) _fe_1(_call, __VA_ARGS__)
#define _fe_3(_call, x, ...) _call(x) _fe_2(_call, __VA_ARGS__)
#define _fe_4(_call, x, ...) _call(x) _fe_3(_call, __VA_ARGS__)
#define _fe_5(_call, x, ...) _call(x) _fe_4(_call, __VA_ARGS__)
#define _fe_6(_call, x, ...) _call(x) _fe_5(_call, __VA_ARGS__)
#define _fe_7(_call, x, ...) _call(x) _fe_6(_call, __VA_ARGS__)
#define _fe_8(_call, x, ...) _call(x) _fe_7(_call, __VA_ARGS__)
#define _fe_9(_call, x, ...) _call(x) _fe_8(_call, __VA_ARGS__)
#define _fe_10(_call, x, ...) _call(x) _fe_9(_call, __VA_ARGS__)
#define _fe_11(_call, x, ...) _call(x) _fe_10(_call, __VA_ARGS__)
#define _fe_12(_call, x, ...) _call(x) _fe_11(_call, __VA_ARGS__)
#define _fe_13(_call, x, ...) _call(x) _fe_12(_call, __VA_ARGS__)
#define _fe_14(_call, x, ...) _call(x) _fe_13(_call, __VA_ARGS__)
#define _fe_15(_call, x, ...) _call(x) _fe_14(_call, __VA_ARGS__)
#define _fe_16(_call, x, ...) _call(x) _fe_15(_call, __VA_ARGS__)
#define _fe_17(_call, x, ...) _call(x) _fe_16(_call, __VA_ARGS__)
#define _fe_18(_call, x, ...) _call(x) _fe_17(_call, __VA_ARGS__)
#define _fe_19(_call, x, ...) _call(x) _fe_18(_call, __VA_ARGS__)
#define _fe_20(_call, x, ...) _call(x) _fe_19(_call, __VA_ARGS__)
#define _fe_21(_call, x, ...) _call(x) _fe_20(_call, __VA_ARGS__)
#define _fe_22(_call, x, ...) _call(x) _fe_21(_call, __VA_ARGS__)
#define _fe_23(_call, x, ...) _call(x) _fe_22(_call, __VA_ARGS__)
#define _fe_24(_call, x, ...) _call(x) _fe_23(_call, __VA_ARGS__)
#define _fe_25(_call, x, ...) _call(x) _fe_24(_call, __VA_ARGS__)
#define _fe_26(_call, x, ...) _call(x) _fe_25(_call, __VA_ARGS__)
#define _fe_27(_call, x, ...) _call(x) _fe_26(_call, __VA_ARGS__)
#define _fe_28(_call, x, ...) _call(x) _fe_27(_call, __VA_ARGS__)
#define CALL_MACRO_X_FOR_EACH(x, ...) \
_GET_NTH_ARG("ignored", ##__VA_ARGS__, \
_fe_28, _fe_27, _fe_26, _fe_25, _fe_24, _fe_23, _fe_22, _fe_21, _fe_20, _fe_19, _fe_18, _fe_17, _fe_16, _fe_15, _fe_14, _fe_13, _fe_12, _fe_11, _fe_10, _fe_9, _fe_8, _fe_7, _fe_6, _fe_5, _fe_4, _fe_3, _fe_2, _fe_1, _fe_0)(x, ##__VA_ARGS__)
#define LOG_EXPR(_X_) do{\
__typeof__(_X_) _Y_ = (_X_);\
const char * _TYPE_CODE_ = @encode(__typeof__(_X_));\
NSString *_STR_ = VTPG_DDToStringFromTypeAndValue(_TYPE_CODE_, &_Y_);\
if(_STR_)\
NSLog(@"%s = %@", #_X_, _STR_);\
else\
NSLog(@"Unknown _TYPE_CODE_: %s for expression %s in function %s, file %s, line %d", _TYPE_CODE_, #_X_, __func__, __FILE__, __LINE__);\
}while(0);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment