57 #include <Foundation/Foundation.h>
71 #if __has_feature(objc_arc)
78 #define OO_BRIDGE( _type ) (__bridge _type)
79 #define OO_TRANSFER( _type ) (__bridge_transfer _type)
80 #define OO_RETAIN( _obj ) _obj
81 #define OO_RETAINCOUNT( _obj ) CFGetRetainCount( OO_BRIDGE(CFTypeRef)_obj )
82 #define OO_AUTORELEASE( _obj ) _obj
83 #define OO_RELEASE( _obj ) (void)(_obj)
84 #define OO_DEALLOC( _obj )
85 #define OO_AUTORETURNS __attribute((ns_returns_autoreleased))
86 #define OO_RETURNS __attribute((ns_returns_retained))
87 #define OO_UNSAFE __unsafe_unretained
88 #define OO_STRONG __strong
91 #define OO_BRIDGE( _type ) (_type)
92 #define OO_TRANSFER( _type ) (_type)
93 #define OO_RETAIN( _obj ) [_obj retain]
94 #define OO_RETAINCOUNT( _obj ) [_obj retainCount]
95 #define OO_AUTORELEASE( _obj ) [_obj autorelease]
96 #define OO_RELEASE( _obj ) [_obj release]
97 #define OO_DEALLOC( _obj ) [super dealloc]
98 #define OO_AUTORETURNS
116 #define OOLog while(0) NSLog
125 static struct { BOOL trace; } _objcpp = {NO};
126 #define OOTrace if( _objcpp.trace ) NSLog
128 #define OOTrace while(0) NSLog
130 #define OORetain OOTrace
131 #define OORelease OOTrace
139 #if defined(OODEBUG) || defined(DEBUG)
140 #define OOWarn OODump
142 static void OODump( NSString *format, ... ) NS_FORMAT_FUNCTION(1,2);
143 static
void OODump( NSString *format, ... ) {
145 va_start(argp, format);
146 NSLogv( format, argp );
150 @throw [NSException alloc];
152 @catch ( NSException *ex ) {
153 NSLog(
@"%@", [ex callStackSymbols] );
169 #define OOEmpty (id)kCFNull
180 #ifdef OODEBUG_NOVALUE
181 #define OONoValue nil
183 #define OONoValue (id)kCFNull
190 #define oo_inline inline
197 #ifndef OOCopyImmutable
198 #define OOCopyImmutable copy // could also be "set" or left undefined (see below)
205 #ifndef OOPoolIfRequired
206 #define OOPoolIfRequired
212 #define OONil (id)nil
213 #define OONull OO_BRIDGE(id)kCFNull
215 #define OOAddress unsigned long
218 #define OOId OOReference<id>
219 #define cOOString const OOString &
220 #define OOStringArray OOArray<OOString>
221 #define cOOStringArray const OOStringArray &
222 #define OOStringArrayArray OOArray<OOStringArray >
223 #define cOOStringArrayArray const OOStringArrayArray &
224 #define OOStringDictionary OODictionary<OOString>
225 #define cOOStringDictionary const OOStringDictionary &
226 #define OOStringDictionaryArray OOArray<OOStringDictionary >
227 #define cOOStringDictionaryArray const OOStringDictionaryArray &
229 #define OOStrArray OOStringArray
230 #define OOStrDict OOStringDictionary
231 #define OOStrDicts OOStringDictionaryArray
232 #define OOStringDict OOStringDictionary
235 #define OONumberArray OOArray<OONumber>
236 #define OONumberDict OODictionary<OONumber>
239 inline NSRange
OORange( NSUInteger start, NSInteger end ) {
240 return NSMakeRange( start, end<0 || end == NSNotFound ? end : end-start );
242 #define OORangeFrom(_start) OORange(_start,NSNotFound)
243 #define OORangeAll() OORangeFrom(0)
244 #define OOSlice OOArray<id>
246 #define OOInt(_val) [NSNumber numberWithInt:_val]
247 #define OODouble(_val) [NSNumber numberWithDouble:_val]
248 #define OORect(_rect) [NSValue valueWithRect:_rect]
251 #define OORef OOReference
252 #define OOPtr OOPointer
253 #define OOStr OOString
254 #define OOStrs OOStringArray
255 #define OOData OOReference<NSData *>
256 #define OODate OOReference<NSDate *>
257 #define OODict OODictionary
258 #define OOHash OODictionary
259 #define OOList OOArray
261 #define OOHome() OOString(NSHomeDirectory())
264 #define OOPrint( _obj ) NSLog( @"%s:%d - %s = %@", __FILE__, __LINE__, #_obj, *_obj )
266 #define OOPrint( _obj ) if(0) _obj
271 template <
typename ETYPE>
class OOArraySub;
272 template <
typename ETYPE>
class OODictionarySub;
273 template <
typename ETYPE>
class OOArraySlice;
274 template <
typename ETYPE>
class OODictionarySlice;
275 template <
typename ETYPE,
typename RTYPE,
typename STYPE>
278 class OONodeArraySub;
312 template <
typename RTYPE>
318 return [typeof *
ref class];
323 OOTrace(
@"%p %s: %@",
this,
"INIT", val != (
id)kCFNull ? (
id)val :
@"(NULL)" );
343 if ( val != nil && val != (
id)kCFNull ) {
344 OORetain(
@"%p %s#%ld: %p = %@",
this,
"RETAIN",
347 if ( old != nil && old != (
id)kCFNull ) {
348 OORelease(
@"%p %s#%ld: %p = %@",
this,
"RELEASE",
363 if ( nilOrCapacity != 0 )
371 #define OO_AUTOTYPE id
373 #define OO_AUTOTYPE RTYPE
401 OOTrace(
@"%p %s %@",
this,
"ALLOC", val );
404 #ifndef OOCopyImmutable
405 #define OOCopyImmutable set
415 RTYPE obj = [val mutableCopyWithZone:NULL];
416 OOTrace(
@"%p %s: %p -> %p = %@",
this,
"COPY", val, obj, obj );
422 RTYPE obj =
OO_TRANSFER(
id)CFPropertyListCreateDeepCopy( NULL,
OO_BRIDGE(CFPropertyListRef)val, kCFPropertyListMutableContainersAndLeaves );
423 OOTrace(
@"%p %s: %p -> %p = %@",
this,
"DEEPCOPY", val, obj, obj );
425 OOWarn(
@"deepcopy failed" );
462 [
alloc() addObject:val];
488 rawset( [NSAutoreleasePool
new] );
545 #ifdef _LIBCPP_STRING
553 template <
typename ETYPE>
556 NSMutableArray *ref2;
586 e2 = va_arg( argp,
id );
592 oo_inline operator int ()
const {
return !*
this ? 0 : (int)[
get() count]; }
600 for(
id object in
get() )
601 if ( callback(
object ) )
608 for(
id object in
get() )
609 out += callback(
object );
614 return filter( callback );
617 return map( callback );
620 #ifdef _LIBCPP_STRING
623 [
alloc() removeAllObjects];
624 for (
typename std::vector<ETYPE>::const_iterator i=vec.begin(); i!=vec.end() ; ++i )
629 std::vector<ETYPE> vec;
630 for ( ETYPE e in
get() )
637 [
alloc() removeAllObjects];
638 for (
typename std::vector<std::string>::const_iterator i=vec.begin(); i!=vec.end() ; ++i )
639 *
this += (ETYPE)[NSMutableString stringWithUTF8String:i->c_str()];
643 std::vector<std::string> vec;
644 for (
id e in
get() )
645 vec.push_back( [[e description] UTF8String] );
666 if ( [val objectForKey:kOOChildren] ) {
667 [
alloc() setArray:[val objectForKey:kOOChildren]];
672 [
alloc() removeAllObjects];
673 for (
int i=0 ; i<keys ; i++ ) {
674 id key = [*keys objectAtIndex:i];
676 *
this += (ETYPE)[val objectForKey:key];
686 return OOArraySub<ETYPE>(
this, sub );
689 return OOArraySub<ETYPE>(
this, sub );
692 return OOArraySub<ETYPE>(
this, sub );
695 return (*
this)[(NSInteger)(
get() ? [
get() indexOfObject:sub] : NSNotFound)];
698 return OOArraySlice<ETYPE>(
this, subs );
721 [
alloc() addObjectsFromArray:val.get()];
727 [
alloc() removeObjectAtIndex:sub < 0 ? (int)*
this+sub : sub];
731 [
alloc() removeObject:val];
735 [
alloc() removeObjectsInArray:val.get()];
742 [
get() removeAllObjects];
743 for (
int i=0 ; i<count ; i++ )
749 for (
int i=0 ; i<*this ; i++ )
750 (*
this)[i] *= val[i];
755 [
get() makeObjectsPerformSelector:sel];
759 for (
int i=0 ; i<*this ; i++ )
760 (*
this)[i] = (ETYPE)block( *(*
this)[i] );
764 #ifdef __clang__ // crashes gcc
765 return *
this += ^ id(
id val) {
766 return [NSString stringWithFormat:
@"%c%@%c", quote, val, quote];
769 for (
int i=0 ; i<*this ; i++ )
770 (*
this)[i] =
OOFormat(
@"%c%@%c", quote, **(*
this)[i], quote );
776 for (
int i=(
int)[in count]-1 ; i>=0 ; i-- ) {
777 id o = [in objectAtIndex:i];
778 if ( !val || [val.get() indexOfObject:o] == NSNotFound )
779 [
get() removeObjectAtIndex:i];
785 for (
int i=0 ; i<[*val count] ; i++ ) {
786 id o = [val.get() objectAtIndex:i];
787 if ( [
get() indexOfObject:o] == NSNotFound )
806 for (
int i=0 ; i<*this ; i++ )
807 arr += [*(*
this)[i] performSelector:sel];
824 for (
int i=0 ; i<*this ; i++ )
825 (*arr[i%split]) += (*this)[i];
838 return [
get() sortedArrayUsingSelector:
@selector(caseInsensitiveCompare:)];
844 return [[
get() reverseObjectEnumerator] allObjects];
858 template <
typename ETYPE>
861 for (
int i=0 ; i<count ; i++ )
866 template <
typename ETYPE>
869 for (
int i=0 ; i<left ; i++ )
870 out[i%count][i/count] = left[i];
911 template <
typename ETYPE>
914 NSMutableDictionary *ref2;
936 va_list argp; va_start(argp, e2);
938 (*
this)[e1] = ETYPE(e2);
939 while ( (e1 = va_arg( argp,
id )) && (e2 = va_arg( argp,
id )) );
945 return [
get() allKeys];
951 for(
id key in
get() ) {
952 ETYPE value = (*this)[key];
953 if ( callback( key, value ) )
961 for(
id key in
get() ) {
962 ETYPE value = (*this)[key];
963 out[key] = callback( key, value );
969 return filter( callback );
972 return map( callback );
975 #ifdef _LIBCPP_STRING
978 [
alloc() removeAllObjects];
979 for (
typename std::map<std::string,ETYPE>::const_iterator i = map.begin(); i != map.end(); ++i )
980 (*
this)[i->first.c_str()] = i->second;
984 std::map<std::string,ETYPE> map;
985 for ( NSString *key in
get() )
986 map[[key UTF8String]] = (*
this)[key];
992 [
alloc() removeAllObjects];
993 for (
typename std::map<std::string,std::string>::const_iterator i = map.begin(); i != map.end(); ++i )
994 (*
this)[i->first.c_str()] = (ETYPE)[NSMutableString stringWithUTF8String:i->second.c_str()];
997 oo_inline operator std::map<std::string,std::string> () {
998 std::map<std::string,std::string> map;
999 for ( NSString *key in
get() )
1000 map[[key UTF8String]] = [[*(*
this)[key] description] UTF8String];
1023 [
alloc() removeAllObjects];
1024 for (
int i=0 ; i<keys ; i+=2 )
1025 #
if OO_WAS_COMPILER_CRASH
1026 (*
this)[*keys[i]] = *values[i+1];
1028 (*this)[[*keys objectAtIndex:i]] = *values[i+1];
1044 [
alloc() removeObjectForKey:val];
1048 [
alloc() removeObjectsForKeys:val];
1052 [
alloc() removeObjectsForKeys:[val allKeys]];
1057 for (
int i=0 ; i<keys ; i++ ) {
1058 id key = [keys objectAtIndex:i];
1059 (*this)[key] *= val[key];
1065 #if OO_WAS_COMPILER_CRASH
1066 for (
id key in [
get() allKeys] )
1072 for (
int i=0 ; i<keys ; i++ ) {
1073 id key = [keys objectAtIndex:i];
1082 for (
int i=0 ; i<keys ; i++ ) {
1083 id key = [keys objectAtIndex:i];
1084 if ( !(*
this)[key] )
1085 (*this)[key] = val[key];
1098 return OODictionarySub<ETYPE>(
this, sub );
1101 return OODictionarySub<ETYPE>(
this, sub );
1105 return OODictionarySub<ETYPE>(
this, sub );
1111 return OODictionarySlice<ETYPE>(
this, subs.get() );
1119 template <
typename ETYPE,
typename RTYPE,
typename STYPE>
1121 friend class OONodeSub;
1131 root = NULL; aref = NULL; dref = NULL;
1136 if ( aref && --aref->references == 0 )
1138 if ( dref && --dref->references == 0 )
1156 OOTrace(
@"%p %s %@",
this,
"VIVIFY", parent );
1160 else if ( ![parent isKindOfClass:c] ) {
1161 OOWarn(
@"Reset: %@ == %@", [parent
class], c );
1162 OO_RELEASE(
set( parent = [parent mutableCopy] ) );
1173 aref->alloc( [RTYPE
class] ) : dref->alloc( [RTYPE
class] )
1175 root ? root->get() : aref ? aref->get( NO ) : dref->get( NO );
1186 return [
get() count];
1189 return [
get() allKeys];;
1198 oo_inline operator const char * ()
const {
return [
get() UTF8String]; }
1205 return OOArraySub<STYPE>( (OODictionarySub<NSMutableArray *> *)
this, sub );
1208 return OOArraySlice<STYPE>( (OODictionarySub<NSMutableArray *> *)
this, sub );
1211 return OODictionarySub<STYPE>( (OODictionarySub<NSMutableDictionary *> *)
this, sub );
1219 return OODictionarySlice<STYPE>( (OODictionarySub<NSMutableDictionary *> *)
this, sub );
1224 OO_RELEASE(
set( [val mutableCopyWithZone:NULL] ) );
1240 oo_inline BOOL operator >= (
const ETYPE val )
const {
return **
this >= val; }
1241 oo_inline BOOL operator <= (
const ETYPE val )
const {
return **
this <= val; }
1242 oo_inline BOOL operator > (
const ETYPE val )
const {
return **
this > val; }
1243 oo_inline BOOL operator < (
const ETYPE val )
const {
return **
this < val; }
1247 oo_inline BOOL operator >= (
const char *val )
const {
return **
this >= ETYPE( val ); }
1248 oo_inline BOOL operator <= (
const char *val )
const {
return **
this <= ETYPE( val ); }
1249 oo_inline BOOL operator > (
const char *val )
const {
return **
this > ETYPE( val ); }
1250 oo_inline BOOL operator < (
const char *val )
const {
return **
this < ETYPE( val ); }
1270 oo_inline ETYPE operator - (
const ETYPE val )
const {
return **
this - val; }
1273 oo_inline ETYPE operator % (
const ETYPE val )
const {
return **
this % val; }
1303 template <
typename ETYPE>
1304 class OOArraySub :
public OOSubscript<ETYPE,NSMutableArray,ETYPE> {
1306 friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1307 friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1310 friend class OONodeArraySub;
1311 friend class OONodeSub;
1315 oo_inline void setIdx( NSInteger sub ) {
1316 idx = sub < 0 ? [this->parent( NO ) count]+sub : sub;
1320 this->root =
ref; setIdx( sub );
1322 oo_inline OOArraySub( OOArraySub<NSMutableArray *> *
ref, NSInteger sub ) {
1323 this->aref =
ref; setIdx( sub );
1325 oo_inline OOArraySub( OODictionarySub<NSMutableArray *> *
ref, NSInteger sub ) {
1326 this->dref =
ref; setIdx( sub );
1331 NSMutableArray *arr = this->parent( NO );
1333 if ( arr == (
id)kCFNull )
1336 OOWarn(
@"%p Excess negative index (%ld) beyond size of array (%ld)",
1338 else if ( idx < [arr count] )
1339 ret = [arr objectAtIndex:idx];
1340 else if ( idx == NSNotFound )
1343 OOWarn(
@"%p Array ref (%ld) beyond end of array (%ld)",
1345 return ret != (id)kCFNull ? ret : nil;
1348 NSMutableArray *arr = this->parent( YES );
1349 NSUInteger count = [arr count];
1353 OOWarn(
@"%p Excess negative index (%ld) beyond size of array (%ld)",
1355 else if ( idx < count )
1356 [arr replaceObjectAtIndex:idx withObject:val];
1357 else if ( idx != NSNotFound ) {
1358 while ( count++ < idx )
1359 [arr addObject:(id)kCFNull];
1360 [arr addObject:val];
1365 oo_inline operator ETYPE () const {
return get(); }
1366 oo_inline operator NSUInteger ()
const {
return idx; }
1374 oo_inline OOArraySub &
operator = (
const OOArraySub<ETYPE> &val ) {
set( val.get() );
return *
this; }
1375 oo_inline OOArraySub &
operator = (
const OODictionarySub<ETYPE> &val ) {
set( val.get() );
return *
this; }
1376 oo_inline OOArraySub &
operator = (
const OOArraySlice<ETYPE> &val ) {
set( val.get() );
return *
this; }
1377 oo_inline OOArraySub &
operator = (
const OODictionarySlice<ETYPE> &val ) {
set( val.get() );
return *
this; }
1383 ETYPE save =
get( NO );
1385 const char *enc = @encode(ETYPE);
1386 if ( enc[0] ==
'@' )
1389 NSMutableArray *arr = this->parent( NO );
1390 if ( 0 <= idx && idx < [arr count] )
1391 [arr removeObjectAtIndex:idx];
1393 OOWarn(
@"%p Attempt to remove index (%ld) beyond end of array (%ld)",
1413 template <
typename ETYPE>
1414 class OODictionarySub :
public OOSubscript<ETYPE,NSMutableDictionary,ETYPE> {
1416 friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1417 friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1418 friend class OODefaultsSub;
1419 friend class OONodeArraySub;
1420 friend class OONodeSub;
1427 this->root =
ref; this->key = sub;
1429 oo_inline OODictionarySub( OOArraySub<NSMutableDictionary *> *
ref,
id sub ) {
1430 this->aref =
ref; this->key = sub;
1432 oo_inline OODictionarySub( OODictionarySub<NSMutableDictionary *> *
ref,
id sub ) {
1433 this->dref =
ref; this->key = sub;
1439 OOWarn(
@"%p OODictionary get with nil key",
this );
1442 id parent = this->parent( NO ),
1443 value = parent != (id)kCFNull ? [parent objectForKey:this->key] : nil;
1444 return value != (id)kCFNull || 0 ? value : nil;
1448 OOWarn(
@"%p OODictionary set with nil key",
this );
1453 [this->parent( YES ) setObject:val forKey:this->key];
1457 oo_inline operator ETYPE () const {
return get(); }
1462 oo_inline OODictionarySub &
operator = (
const OOArraySub<ETYPE> &val ) {
set( val.get() );
return *
this; }
1463 oo_inline OODictionarySub &
operator = (
const OODictionarySub<ETYPE> &val ) {
set( val.get() );
return *
this; }
1464 oo_inline OODictionarySub &
operator = (
const OOArraySlice<ETYPE> &val ) {
set( val.get() );
return *
this; }
1465 oo_inline OODictionarySub &
operator = (
const OODictionarySlice<ETYPE> &val ) {
set( val.get() );
return *
this; }
1471 ETYPE save =
get( NO );
1473 const char *enc = @encode(ETYPE);
1474 if ( enc[0] ==
'@' )
1477 [this->parent( NO ) removeObjectForKey:this->key];
1498 template<typename ETYPE>
1501 friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1502 friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1508 oo_inline void setSlice(
const NSRange &sub ) {
1509 NSUInteger parentCount = [this->
parent( NO ) count];
1510 if ( (NSInteger)((slice = sub).location) < 0 )
1511 slice.location = parentCount+slice.location;
1512 if ( slice.length == NSNotFound )
1513 slice.length = parentCount-slice.location;
1514 else if ( slice.length > parentCount-slice.location ) {
1515 OOWarn(
@"%p Slice length (%ld) beyond availble (%ld-%ld)",
1517 slice.length = parentCount-slice.location;
1522 this->
root =
ref; setSlice( sub );
1524 oo_inline OOArraySlice( OOArraySub<NSMutableArray *> *
ref,
const NSRange &sub ) {
1525 this->
aref =
ref; setSlice( sub );
1527 oo_inline OOArraySlice( OODictionarySub<NSMutableArray *> *
ref,
const NSRange &sub ) {
1528 this->
dref =
ref; setSlice( sub );
1533 return [this->
parent( NO ) subarrayWithRange:slice];
1537 oo_inline operator NSArray * ()
const {
return get(); }
1540 return [
get() isEqualToArray:in.get()];
1546 [this->
parent( YES ) replaceObjectsInRange:slice withObjectsFromArray:in];
1549 oo_inline OOArraySlice &operator = ( const OOArraySlice<ETYPE> &in ) {
1557 [this->
parent( NO ) removeObjectsInRange:slice];
1577 template<typename ETYPE>
1578 class OODictionarySlice : public
OOSubscript<
OOArray<ETYPE>,NSMutableDictionary,ETYPE> {
1580 friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1581 friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1586 this->
root =
ref; slice = sub;
1588 oo_inline OODictionarySlice( OOArraySub<NSMutableDictionary *> *
ref, NSMutableArray *sub ) {
1589 this->
aref =
ref; slice = sub;
1591 oo_inline OODictionarySlice( OODictionarySub<NSMutableDictionary *> *
ref, NSMutableArray *sub ) {
1592 this->
dref =
ref; slice = sub;
1596 return [this->
parent( NO ) objectsForKeys:slice notFoundMarker:(
id)kCFNull];
1600 oo_inline operator NSArray * ()
const {
return get(); }
1603 return [
get() isEqualToArray:in.get()];
1609 if ( (
int)in != (
int)slice )
1610 OOWarn(
@"Slice assignment with key count [%d] different to value count [%d] - %@ c.f. %@",
1611 (
int)slice, (
int)in, *slice, *in );
1613 for (
int i=0 ; i<slice ; i++ )
1614 dict[slice[i]] = in[i];
1625 [this->
parent( NO ) removeObjectsForKeys:slice];