Objective-C++ Preprocessor  5.0 with ARC & GC
C++ classes to enhance syntax and manage reference counting.
objcpp.h
Go to the documentation of this file.
1 /*
2  * objcpp.h - reference counting wrappers for Objective-C containers.
3  * ========
4  *
5  * Created by John Holdsworth on 01/04/2009.
6  * Copyright 2009 © John Holdsworth. All Rights Reserved.
7  *
8  * $Id: //depot/ObjCpp/objcpp.h#116 $
9  * $DateTime: 2014/02/04 19:31:31 $
10  *
11  * C++ classes to wrap up XCode classes for operator overload of
12  * useful operations such as access to NSArrays and NSDictionary
13  * by subscript or NSString operators such as + for concatenation.
14  *
15  * This works as the Apple Objective-C compiler supports source
16  * which mixes C++ with objective C. To enable this: for each
17  * source file which will include/import this header file, select
18  * it in Xcode and open it's "Info". To enable mixed compilation,
19  * for the file's "File Type" select: "sourcecode.cpp.objcpp".
20  *
21  * For bugs or ommisions please email objcpp@johnholdsworth.com
22  *
23  * Home page for updates and docs: http://objcpp.johnholdsworth.com
24  *
25  * If you find it useful please send a donation via paypal to account
26  * objcpp@johnholdsworth.com. Thanks.
27  *
28  * License
29  * =======
30  *
31  * You may make commercial use of this source in applications without
32  * charge but not sell it as source nor can you remove this notice from
33  * this source if you redistribute. You can make any changes you like
34  * to this code before redistribution but you must annotate them below.
35  *
36  * For further details http://objcpp.johnholdsworth.com/license.html
37  *
38  * THIS CODE IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND EITHER
39  * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
40  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
41  *
42  * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
43  * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
44  * THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
45  * ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT
46  * OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
47  * TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED
48  * BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
49  * ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
50  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
51  *
52  */
53 
54 #ifndef _objcpp_h_
55 #define _objcpp_h_
56 
57 #include <Foundation/Foundation.h>
58 
59 /************************************************************************
60  Add the following to your project's "Other Sources/Project_Prefix.pch"
61  ************************************************************************
62 
63  // precompile objcpp //
64 #import "objcpp.h"
65 #import "objsql.h"
66 
67  */
68 
69 // Automatic referrence counting support
70 #ifdef __clang__
71 #if __has_feature(objc_arc)
72 #define OO_ARC
73 #endif
74 #endif
75 
76 // Used to write code that compiles both with and without ARC
77 #ifdef OO_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
89 #define OO_WEAK _weak
90 #else
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
99 #define OO_RETURNS
100 #define OO_UNSAFE
101 #define OO_STRONG
102 #define OO_WEAK
103 #endif
104 
105 #ifdef __cplusplus
106 /*===========================================================================*/
107 /*============================== Overrides ==================================*/
108 
109 /**
110  For logging only during development
111  */
112 
113 #ifdef DEBUG
114 #define OOLog NSLog
115 #else
116 #define OOLog while(0) NSLog
117 #endif
118 
119 /**
120  For detailed debugging
121  */
122 
123 #ifndef OOTrace
124 #ifdef OODEBUG
125 static struct { BOOL trace; } _objcpp = {NO};
126 #define OOTrace if( _objcpp.trace ) NSLog
127 #else
128 #define OOTrace while(0) NSLog
129 #endif
130 #define OORetain OOTrace
131 #define OORelease OOTrace
132 #endif
133 
134 /**
135  Function to log warning messages
136  */
137 
138 #ifndef OOWarn
139 #if defined(OODEBUG) || defined(DEBUG)
140 #define OOWarn OODump
141 // stack traces for debug warnings
142 static void OODump( NSString *format, ... ) NS_FORMAT_FUNCTION(1,2);
143 static void OODump( NSString *format, ... ) {
144  va_list argp;
145  va_start(argp, format);
146  NSLogv( format, argp );
147  va_end( argp );
148 
149  @try {
150  @throw [NSException alloc];
151  }
152  @catch ( NSException *ex ) {
153  NSLog( @"%@", [ex callStackSymbols] );
154  }
155 
156  // (*(int *)0)++; // invalid memory access hands control over to debugger...
157 }
158 #else
159 #define OOWarn NSLog
160 #endif
161 #endif
162 
163 /**
164  Inital value for uninitialised references. Use (id)kCFNull to detect messaging of unititialsed objects.
165  */
166 
167 #ifndef OOEmpty
168 #ifdef OOSTRICT
169 #define OOEmpty (id)kCFNull
170 #else
171 #define OOEmpty nil
172 #endif
173 #endif
174 
175 /**
176  Value to use in place of nil in NSArray and NSDictioanry. Set to nil to trap attempts to assign nil.
177  */
178 
179 #ifndef OONoValue
180 #ifdef OODEBUG_NOVALUE
181 #define OONoValue nil
182 #else
183 #define OONoValue (id)kCFNull
184 #endif
185 #endif
186 
187 #ifdef OODEBUG
188 #define oo_inline /* */
189 #else
190 #define oo_inline inline
191 #endif
192 
193 /**
194  Policy: Determines whether asignment from immutables automatically takes "mutableCopy".
195  */
196 
197 #ifndef OOCopyImmutable
198 #define OOCopyImmutable copy // could also be "set" or left undefined (see below)
199 #endif
200 
201 /**
202  In threads without their own autorelease pool you may need to define this as "OOPool pool"
203  */
204 
205 #ifndef OOPoolIfRequired
206 #define OOPoolIfRequired /* OOPool pool */
207 #endif
208 
209 /**
210  If you ask me this is how "nil" should be defined
211  */
212 #define OONil (id)nil
213 #define OONull OO_BRIDGE(id)kCFNull
214 #define OOLong long
215 #define OOAddress unsigned long
216 
217 // containers for OOStrings
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 &
228 
229 #define OOStrArray OOStringArray
230 #define OOStrDict OOStringDictionary
231 #define OOStrDicts OOStringDictionaryArray
232 #define OOStringDict OOStringDictionary
233 
234 // containers for OONumbers
235 #define OONumberArray OOArray<OONumber>
236 #define OONumberDict OODictionary<OONumber>
237 
238 // for slicing arrays
239 inline NSRange OORange( NSUInteger start, NSInteger end ) {
240  return NSMakeRange( start, end<0 || end == NSNotFound ? end : end-start );
241 }
242 #define OORangeFrom(_start) OORange(_start,NSNotFound)
243 #define OORangeAll() OORangeFrom(0)
244 #define OOSlice OOArray<id>
245 
246 #define OOInt(_val) [NSNumber numberWithInt:_val]
247 #define OODouble(_val) [NSNumber numberWithDouble:_val]
248 #define OORect(_rect) [NSValue valueWithRect:_rect]
249 
250 // variations as per taste
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
260 
261 #define OOHome() OOString(NSHomeDirectory())
262 
263 #ifdef OODEBUG
264 #define OOPrint( _obj ) NSLog( @"%s:%d - %s = %@", __FILE__, __LINE__, #_obj, *_obj )
265 #else
266 #define OOPrint( _obj ) if(0) _obj
267 #endif
268 
269 // forward referenced class templates
270 template <typename ETYPE> class OODictionary;
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>
277 class OOString;
278 class OONodeArraySub;
279 class OONodeSub;
280 class OONode;
281 
282 /*=================================================================================*/
283 /*============================== Basic ref managment ========================*/
284 
285 /**
286  A class managing basic ref counting references retain/release mechansim for use in
287  instance variables which will not allow constructors or destructors. Use the &operator
288  to get a pointer with "autorelease" scope for use in the rest of your program.
289 
290  To free the ref either assign nil references the "=" operator or call use the ~ operator
291  which returns a transient ref. Use &~var to free the ref with autorelrease scope.
292 
293  Usage:
294  <pre>
295  OOReference<NSString *> immutableRef = @"STRING"; // take referrence to a string
296  OOReference<NSMutableArray *> mutableRef <<= [NSArray array]; // take mutable copy
297  NSMutableArray *ptr = &amp;mutableRef; // get autoreleasing pointer to original object
298  NSMutableArray *ptr = *mutableRef; // get pointer to original object
299  ~mutableRef; // clear out pointer and remove "release" object.
300 
301  - (NSString *)function:(NSString *)str {
302  OOReference<NSString *> ref = str; // take ref
303 
304  // do something
305 
306  return &amp;str; // get autoreleasing pointer to return
307  // ref is discarded when object destructed on function exit.
308  }
309  </pre>
310  */
311 
312 template <typename RTYPE>
313 class OOReference {
314  RTYPE ref;
315 
316  // determine Object-C class of reference
317  oo_inline Class classOfReference() const {
318  return [typeof *ref class];
319  }
320 
321  // initialise ref
322  oo_inline RTYPE init( RTYPE val = OOEmpty ) OO_RETURNS {
323  OOTrace( @"%p %s: %@", this, "INIT", val != (id)kCFNull ? (id)val : @"(NULL)" );
324  ref = nil;
325  return set( val );
326  }
327 
328 protected:
329  // clear out referrence
331  OOTrace( @"%p %s: %p = %@", this, "DESTRUCT", ref, ref );
332  rawset( (RTYPE)nil );
333  }
334 
335  // replace reference
336 #ifdef __OBJC_GC__
337  oo_inline virtual id rawset( RTYPE val ) OO_RETURNS {
338 #else
339  oo_inline RTYPE rawset( RTYPE val ) OO_RETURNS {
340 #endif
341  RTYPE old = ref;
342  ref = val;
343  if ( val != nil && val != (id)kCFNull ) {
344  OORetain( @"%p %s#%ld: %p = %@", this, "RETAIN",
345  (OOLong)OO_RETAINCOUNT( val ), val, val );
346  }
347  if ( old != nil && old != (id)kCFNull ) {
348  OORelease( @"%p %s#%ld: %p = %@", this, "RELEASE",
349  (OOLong)OO_RETAINCOUNT( old ), old, old );
350  OO_RELEASE( old );
351  old = nil;
352  }
353  return ref;
354  }
355 
356  // replace referrence with retain
357  oo_inline RTYPE set( RTYPE val ) OO_RETURNS {
358  return rawset( OO_RETAIN( val ) );
359  }
360 
361  // assignment from nil comes through as 0
362  oo_inline RTYPE set( NSUInteger nilOrCapacity ) OO_RETURNS {
363  if ( nilOrCapacity != 0 )
364  rawset( [[classOfReference() alloc] initWithCapacity:nilOrCapacity] );
365  else
366  set( OONil );
367  return ref;
368  }
369 
370 #ifdef OO_ARC
371 #define OO_AUTOTYPE id
372 #else
373 #define OO_AUTOTYPE RTYPE
374 #endif
376  return ref ? ref : OO_AUTORELEASE( [[classOfReference() alloc] init] );
377  }
378  // get ref with "autorelease" scope
380  return OO_AUTORELEASE( OO_RETAIN( get() ) );
381  }
382 
383 public:
384  // constructors to avoid shallow copy
386  ///oo_inline OOReference( id obj ) { init( obj ); }
387  oo_inline OOReference( RTYPE obj ) { init( obj ); }
388  oo_inline OOReference( CFNullRef obj ) { init( OO_BRIDGE(id)obj ); }
389  oo_inline OOReference( const OOReference &val ) { init( val.get() ); }
390  oo_inline OOReference( const OOArraySub<RTYPE> &obj ) { init( obj.get() ); }
391  oo_inline OOReference( const OODictionarySub<RTYPE> &obj ) { init( obj.get() ); }
392 
393  oo_inline void *ptr() {
394  return this;
395  }
396 
397  // allocate new ref from RTYPE specified
399  if ( !*this ) {
400  RTYPE val = [[classOfReference() alloc] init];
401  OOTrace( @"%p %s %@", this, "ALLOC", val );
402  rawset( val );
403  }
404 #ifndef OOCopyImmutable
405 #define OOCopyImmutable set
406  // alternate strategy to ensure mutability
407  // does not work for objects in containers
408  else if ( [ref class] != classOfReference() )
409  copy( ref );
410 #endif
411  return ref;
412  }
413  // copy any immutable objects
414  oo_inline void copy( RTYPE val ) {
415  RTYPE obj = [val mutableCopyWithZone:NULL];
416  OOTrace( @"%p %s: %p -> %p = %@", this, "COPY", val, obj, obj );
417  rawset( obj );
418  }
419 
420  // deep copy any plist
422  RTYPE obj = OO_TRANSFER(id)CFPropertyListCreateDeepCopy( NULL, OO_BRIDGE(CFPropertyListRef)val, kCFPropertyListMutableContainersAndLeaves );
423  OOTrace( @"%p %s: %p -> %p = %@", this, "DEEPCOPY", val, obj, obj );
424  if ( val && !obj )
425  OOWarn( @"deepcopy failed" );
426  rawset( obj );
427  return *this;
428  }
429 
430  // get existing ref
431  oo_inline RTYPE get() const OO_RETURNS {
432  return ref;
433  }
434 
435  // for cast operator, somehow OO_RETURNS is not required
436  oo_inline operator RTYPE () const /*OO_RETURNS*/ { return get(); }
437  oo_inline RTYPE operator -> () const OO_RETURNS { return get(); }
439  oo_inline RTYPE operator * () const OO_RETURNS { return !*this ? nil : get(); }
440  oo_inline BOOL operator ! () const { return !ref || ref == (id)kCFNull; }
441 
442  // assign (mutable) now deep copy of plist from source
444  return deepcopy( val.get() );
445  }
447  return deepcopy( val );
448  }
449 
450  // assigment by referenc
451  oo_inline OOReference &operator = ( const OOReference &val ) { set( val.get() ); return *this; }
452  oo_inline OOReference &operator = ( CFNullRef val ) { set( val ); return *this; }
453  oo_inline OOReference &operator = ( RTYPE val ) { set( val ); return *this; }
454  oo_inline OOReference &operator = ( int val ) { set( val ); return *this; }
455 
456  // comparison
457  oo_inline BOOL operator == ( const OOReference &val ) const { return [get() isEqual:val.get()]; }
458  oo_inline BOOL operator != ( const OOReference &val ) const { return !(*this == val); }
459 
460  /// for OOArray<id>
462  [alloc() addObject:val];
463  return *this;
464  }
465 
466  // might be useful...
467  oo_inline id operator [] ( NSString *key ) const { return [ref valueForKeyPath:key]; }
468 
470  // take temporary ref and return it
471  // in case &~var construct is used
472  OOReference save = ref;
473  this->destruct();
474  return save;
475  }
476 
478 };
479 
480 /**
481  Scope based auto-release pool.
482  */
483 
484 #ifndef OO_ARC
485 class OOPool : public OOReference<NSAutoreleasePool *> {
486 public:
488  rawset( [NSAutoreleasePool new] );
489  }
490 };
491 #else
492 class OOPool {
493 public:
494  oo_inline OOPool() {
495  }
496 };
497 #endif
498 
499 /*=================================================================================*/
500 /*=============================== Array classes ===================================*/
501 
502 
503 /**
504  NSMutableArray wrapper allowing subscript syntax by index and various other operators.
505  The integer value of an OArray object is the number of elements e.g. "for ( i=0 ; i<array ; i++ )".
506 
507  <table cellspacing=0><tr><th>operator<th>inplace<th>binary<th>argument
508  <tr><td>assignment<td>&nbsp;<td>=<td>array
509  <tr><td>copy<td>&nbsp;<td>&lt;&lt;=<td>array
510  <tr><td>add object(s)<td>+=<td>+<td>object (or array)
511  <tr><td>remove object(s)<td>-=<td>-<td>object (or array)
512  <tr><td>replicate members(s)<td>*=<td>*<td>count
513  <tr><td>split alternate members<td><td>/<td>count e.g 2 for even/odd members
514  <tr><td>filter array<td>&=<td>&<td>array
515  <tr><td>merge array<td>|=<td>|<td>array
516  <tr><td>subscript<td>&nbsp;<td>[]<td>int, object or range
517  </table>
518 
519  Usage:
520  <pre>
521  \@interface ExampleClass {
522  OOArray array;
523  }
524  \@end
525 
526  \@implementation ExampleClass
527  - (void) aFunction {
528  array += @"STRING"; // append to array
529  array[1] = @"STRING"; // set position directly
530  NSString *str = &amp;array[1]; // take polinter to item 1
531  ~array[0]; // remove element at position 0
532  }
533 
534  - (NSMutableArray *)function {
535  OOArray<NSString *> array; // declare array of strings
536  for ( int i=0 ; i<20 )
537  array[i] = @"STRING";
538  return &amp;array; // return autoreleasing pointer to array allocated
539  }
540 
541  \@end
542  </pre>
543  */
544 
545 #ifdef _LIBCPP_STRING
546 #import <vector>
547 #import <map>
548 #endif
549 
550 class OOStringSearch;
551 typedef id (^OOBlock)(id);
552 
553 template <typename ETYPE>
554 class OOArray : public OOReference<NSMutableArray *> {
555 #ifdef __OBJC_GC__
556  NSMutableArray *ref2;
557  oo_inline virtual id rawset( NSMutableArray *val ) OO_RETURNS {
558  return OOReference<NSMutableArray *>::rawset( ref2 = val );
559  }
560 #endif
561 public:
563  oo_inline OOArray( id obj ) { *this = obj; }
564  oo_inline OOArray( CFNullRef obj ) { set( OO_BRIDGE(id)obj ); }
565  oo_inline OOArray( const OOArray &arr ) { *this = arr; }
566  oo_inline OOArray( const OOArraySub<ETYPE> &sub ) { *this = sub; }
567  oo_inline OOArray( const OODictionarySub<ETYPE> &sub ) { *this = sub; }
569  oo_inline OOArray( const OOArraySlice<ETYPE> &sub ) { *this = sub; }
570  oo_inline OOArray( const OODictionarySlice<ETYPE> &sub ) { *this = sub; }
571  oo_inline OOArray( const OOReference<NSMutableArray *> &arr ) { *this = arr; }
572  oo_inline OOArray( const OOReference<NSMutableDictionary *> &arr ) { *this = arr; }
573  oo_inline OOArray( const OONodeSub &sub );
574  oo_inline OOArray( int nilOrCapacity ) { *this = nilOrCapacity; }
575  oo_inline OOArray( long nilOrCapacity ) { *this = nilOrCapacity; }
576  oo_inline OOArray( NSMutableArray *arr ) { *this = arr; }
577  oo_inline OOArray( NSArray *arr ) { *this = arr; }
578  oo_inline OOArray( const char *val ) { *this = val; }
579  oo_inline OOArray( const char **val ) { *this = val; }
580  oo_inline OOArray( id e1, id e2, ... ) NS_REQUIRES_NIL_TERMINATION {
581  va_list argp;
582  va_start(argp, e2);
583  *this += ETYPE(e1);
584  while ( e2 ) {
585  *this += ETYPE(e2);
586  e2 = va_arg( argp, id );
587  }
588  va_end( argp );
589  }
590 
591  oo_inline NSMutableArray *operator & () const { return autoget(); }
592  oo_inline operator int () const { return !*this ? 0 : (int)[get() count]; }
593  oo_inline int fetch( id parent /*= nil*/, cOOString sql /*= OOString( OONil )*/ );
594 
595  oo_inline OOString join( cOOString sep /*= OOString( @" " )*/ ) const;
596 
597 #ifdef __clang__
598  oo_inline OOArray filter( BOOL (^callback)( id object ) ) {
599  OOArray out;
600  for( id object in get() )
601  if ( callback( object ) )
602  out += object;
603  return out;
604  }
605 
606  oo_inline OOArray map( id (^callback)( id object ) ) {
607  OOArray out;
608  for( id object in get() )
609  out += callback( object );
610  return out;
611  }
612 
613  oo_inline OOArray operator & ( BOOL (^callback)( id object ) ) {
614  return filter( callback );
615  }
616  oo_inline OOArray operator & ( id (^callback)( id object ) ) {
617  return map( callback );
618  }
619 
620 #ifdef _LIBCPP_STRING
621  oo_inline OOArray( const std::vector<ETYPE> &val ) { *this = val; }
622  oo_inline OOArray &operator = ( const std::vector<ETYPE> &vec ) {
623  [alloc() removeAllObjects];
624  for ( typename std::vector<ETYPE>::const_iterator i=vec.begin(); i!=vec.end() ; ++i )
625  *this += *i;
626  return *this;
627  }
628  oo_inline operator std::vector<ETYPE> () const {
629  std::vector<ETYPE> vec;
630  for ( ETYPE e in get() )
631  vec.push_back( e );
632  return vec;
633  }
634 
635  oo_inline OOArray( const std::vector<std::string> &val ) { *this = val; }
636  oo_inline OOArray &operator = ( const std::vector<std::string> &vec ) {
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()];
640  return *this;
641  }
642  oo_inline operator std::vector<std::string> () const {
643  std::vector<std::string> vec;
644  for ( id e in get() )
645  vec.push_back( [[e description] UTF8String] );
646  return vec;
647  }
648 #endif
649 #endif
650 
651  oo_inline OOArray &operator = ( id val ) { set( val ); return *this; }
652  oo_inline OOArray &operator = ( NSMutableArray *val ) { set( val ); return *this; }
653  oo_inline OOArray &operator = ( NSArray *val ) { OOCopyImmutable( (NSMutableArray *)val ); return *this; }
654  oo_inline OOArray &operator = ( int nilOrCapacity ) { set( nilOrCapacity ); return *this; }
655  oo_inline OOArray &operator = ( long nilOrCapacity ) { set( nilOrCapacity ); return *this; }
656  oo_inline OOArray &operator = ( const OOArray &val ) { set( val.get() ); return *this; }
657  oo_inline OOArray &operator = ( const OOArraySub<ETYPE> &val ) { set( val.get() ); return *this; }
658  oo_inline OOArray &operator = ( const OODictionarySub<ETYPE> &val ) { set( val.get() ); return *this; }
659  oo_inline OOArray &operator = ( const OOArraySlice<ETYPE> &val ) { OOCopyImmutable( val.get() ); return *this; }
660  oo_inline OOArray &operator = ( const OODictionarySlice<ETYPE> &val ) { OOCopyImmutable( val.get() ); return *this; }
661  oo_inline OOArray &operator = ( const OOStringSearch &search );
662  oo_inline OOArray &operator = ( const OOReference<NSMutableArray *> &val ) { set( val.get() ); return *this; }
664 #if 0
665  // objxml.h support
666  if ( [val objectForKey:kOOChildren] ) {
667  [alloc() setArray:[val objectForKey:kOOChildren]];
668  return *this;
669  }
670 #endif
671  OOArray<id> keys = [val allKeys];
672  [alloc() removeAllObjects];
673  for ( int i=0 ; i<keys ; i++ ) {
674  id key = [*keys objectAtIndex:i];
675  *this += (ETYPE)key;
676  *this += (ETYPE)[val objectForKey:key];
677  }
678  return *this;
679  }
680  oo_inline OOArray &operator = ( const char *val );
681  oo_inline OOArray &operator = ( const char **val );
682  oo_inline OOArray &operator = ( const OONodeSub &sub );
683 
684  // subscript into array
685  oo_inline OOArraySub<ETYPE> operator [] ( int sub ) const {
686  return OOArraySub<ETYPE>( this, sub );
687  }
688  oo_inline OOArraySub<ETYPE> operator [] ( long sub ) const {
689  return OOArraySub<ETYPE>( this, sub );
690  }
691  oo_inline OOArraySub<ETYPE> operator [] ( NSUInteger sub ) const {
692  return OOArraySub<ETYPE>( this, sub );
693  }
694  oo_inline OOArraySub<ETYPE> operator [] ( ETYPE sub ) const {
695  return (*this)[(NSInteger)(get() ? [get() indexOfObject:sub] : NSNotFound)];
696  }
697  oo_inline OOArraySlice<ETYPE> operator [] ( const NSRange &subs ) const {
698  return OOArraySlice<ETYPE>( this, subs );
699  }
700 
701  oo_inline BOOL operator == ( NSArray *val ) const { return [get() isEqualToArray:val]; }
702  oo_inline BOOL operator != ( NSArray *val ) const { return !operator == ( val ); }
703  oo_inline BOOL operator == ( NSMutableArray *val ) const { return [get() isEqualToArray:val]; }
704  oo_inline BOOL operator != ( NSMutableArray *val ) const { return !operator == ( val ); }
705  oo_inline BOOL operator == ( const OOArray &val ) const { return [get() isEqualToArray:val]; }
706  oo_inline BOOL operator != ( const OOArray &val ) const { return !operator == ( val ); }
707  ///oo_inline BOOL operator == ( const char *val ) const { return **this == OOString( val ); }
708  ///oo_inline BOOL operator != ( const char *val ) const { return **this != OOString( val ); }
709 
710  // add elements
711  oo_inline OOArray &operator += ( ETYPE val );
712  oo_inline OOArray &operator += ( const char *val ) {
713  *this += (ETYPE)val;
714  return *this;
715  }
716  oo_inline OOArray &operator += ( NSArray *val ) {
717  *this += OOArray( val );
718  return *this;
719  }
721  [alloc() addObjectsFromArray:val.get()];
722  return *this;
723  }
724 
725  // remove elements (not returning it)
726  oo_inline OOArray &operator -= ( int sub ) {
727  [alloc() removeObjectAtIndex:sub < 0 ? (int)*this+sub : sub];
728  return *this;
729  }
730  oo_inline OOArray &operator -= ( ETYPE val ) {
731  [alloc() removeObject:val];
732  return *this;
733  }
734  oo_inline OOArray &operator -= ( const OOReference<NSMutableArray *> &val ) {
735  [alloc() removeObjectsInArray:val.get()];
736  return *this;
737  }
738 
739  // replicate
740  oo_inline OOArray &operator *= ( NSUInteger count ) {
741  OO_STRONG NSArray *arr = [get() copy];
742  [get() removeAllObjects];
743  for ( int i=0 ; i<count ; i++ )
744  *this += arr;
745  OO_RELEASE( arr );
746  return *this;
747  }
748  oo_inline OOArray &operator *= ( const OOArray<ETYPE> &val ) {
749  for ( int i=0 ; i<*this ; i++ )
750  (*this)[i] *= val[i];
751  return *this;
752  }
753 
755  [get() makeObjectsPerformSelector:sel];
756  return *this;
757  }
759  for ( int i=0 ; i<*this ; i++ )
760  (*this)[i] = (ETYPE)block( *(*this)[i] );
761  return *this;
762  }
763  oo_inline OOArray &operator += ( char quote ) {
764 #ifdef __clang__ // crashes gcc
765  return *this += ^ id(id val) {
766  return [NSString stringWithFormat:@"%c%@%c", quote, val, quote];
767  };
768 #else
769  for ( int i=0 ; i<*this ; i++ )
770  (*this)[i] = OOFormat( @"%c%@%c", quote, **(*this)[i], quote );
771  return *this;
772 #endif
773  }
774  oo_inline OOArray &operator &= ( const OOReference<NSMutableArray *> &val ) {
775  OO_STRONG NSArray *in = [get() copy];
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];
780  }
781  OO_RELEASE( in );
782  return *this;
783  }
785  for ( int i=0 ; i<[*val count] ; i++ ) {
786  id o = [val.get() objectAtIndex:i];
787  if ( [get() indexOfObject:o] == NSNotFound )
788  [get() addObject:o];
789  }
790  return *this;
791  }
792 
793 
794  // binary equivalents
795  oo_inline OOArray operator + ( ETYPE val ) const {
796  OOArray arr; arr <<= noalloc(); arr += val; return arr;
797  }
798  oo_inline OOArray operator + ( char val ) const {
799  OOArray arr; arr <<= noalloc(); arr += val; return arr;
800  }
801  oo_inline OOArray operator - ( ETYPE val ) const {
802  OOArray arr; arr <<= noalloc(); arr -= val; return arr;
803  }
804  oo_inline OOArray operator + ( SEL sel ) const {
805  OOArray<id> arr;
806  for ( int i=0 ; i<*this ; i++ )
807  arr += [*(*this)[i] performSelector:sel];
808  return arr;
809  }
810 
812  OOArray arr; arr <<= noalloc(); arr += val; return arr;
813  }
814  oo_inline OOArray operator - ( const OOReference<NSMutableArray *> &val ) const {
815  OOArray arr; arr <<= noalloc(); arr -= val; return arr;
816  }
817 #if 000
819  OOArray arr; arr <<= noalloc(); arr *= val; return arr;
820  }
821 #endif
824  for ( int i=0 ; i<*this ; i++ )
825  (*arr[i%split]) += (*this)[i];
826  return arr;
827  }
829  OOArray arr; arr <<= noalloc(); arr &= val; return arr;
830  }
832  OOArray arr; arr <<= noalloc(); arr |= val; return arr;
833  }
834 
835  // sort array (of strings)
838  return [get() sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
839  }
840 
841  // array in reverse order
842  oo_inline OOArray operator - () const {
844  return [[get() reverseObjectEnumerator] allObjects];
845  }
846 
847  // shift first element
848  oo_inline ETYPE operator -- () {
849  return ~(*this)[0];
850  }
851 
852  // pop last element
853  oo_inline ETYPE operator -- ( int ) {
854  return ~(*this)[-1];
855  }
856 };
857 
858 template <typename ETYPE>
860  OOArray<ETYPE> out( (int)left*count );
861  for ( int i=0 ; i<count ; i++ )
862  out += left;
863  return out;
864 }
865 
866 template <typename ETYPE> ////
868  OOArray<ETYPE> out( count );
869  for ( int i=0 ; i<left ; i++ )
870  out[i%count][i/count] = left[i];
871  return out;
872 }
873 
874 /*=================================================================================*/
875 /*============================== Dictionary classes ===============================*/
876 
877 /**
878  NSMutableDictionary wrapper for use in instance variables which allows subscripting
879  by the key value. Use &~dict[@"key"] to remove the entry and return it with expression
880  or autorelease scope. Subscripting can be applied recusively. ETYPE is type of leaf node.
881 
882  Operators:
883  <table cellspacing=0><tr><th>operator<th>inplace<th>arguments
884  <tr><td>take referernce<td>=<td>dictionary
885  <tr><td>take copy<td>&lt;&lt;=<td>dictionary
886  <tr><td>merge entries<td>+=<td>dictionary
887  <tr><td>remove entries<td>-=<td>key or array
888  <tr><td>sbuscript<td>[]<td>object (key) or "slice" of keys
889  </table>
890 
891  Usage:
892  <pre>
893 
894  - (void)function:(OODictionary<NSString *> &)dict {
895  dict[@"ONE"][@"TWO"][@"THREE"] = @"Four"; // set valule
896  NSString *str = *dict[@"ONE"][@"TWO"][@"THREE"]; // get value
897  ~dict[@"ONE"][@"TWO"][@"THREE"]; // delete value
898  // pointer "str" is invalid at this point
899  }
900 
901  - (void)function:(NSMutableDictionary *)dict {
902  OODictionary<OOString> ref <<= dict; // initialise mutable copy
903  ref[@"KEY"] <<= @"";
904  for ( int i=0 ; i<10 ; i++ )
905  ref[@"KEY"] += "ABC";
906  }
907 
908  </pre>
909  */
910 
911 template <typename ETYPE>
912 class OODictionary : public OOReference<NSMutableDictionary *> {
913 #ifdef __OBJC_GC__
914  NSMutableDictionary *ref2;
915 protected:
916  oo_inline virtual id rawset( NSMutableDictionary *val ) OO_RETURNS {
917  return OOReference<NSMutableDictionary *>::rawset( ref2 = val );
918  }
919 #endif
920 public:
922  oo_inline OODictionary( id obj ) { *this = obj; }
923  oo_inline OODictionary( CFNullRef obj ) { set( OO_BRIDGE(id)obj ); }
924  oo_inline OODictionary( const OODictionary &dict ) { *this = dict; }
925  oo_inline OODictionary( const OOArraySub<ETYPE> &sub ) { *this = sub; }
926  oo_inline OODictionary( const OODictionarySub<ETYPE> &sub ) { *this = sub; }
928  oo_inline OODictionary( const OOReference<NSMutableArray *> &val ) { *this = val; }
929  oo_inline OODictionary( const OOStringSearch &search ) { *this = search; }
930  oo_inline OODictionary( int nilOrCapacity ) { *this = nilOrCapacity; }
931  oo_inline OODictionary( NSMutableDictionary *dict ) { *this = dict; }
932  oo_inline OODictionary( NSDictionary *dict ) { *this = dict; }
933  oo_inline OODictionary( const char *val ) { *this = val; }
934  oo_inline OODictionary( const char **val ) { *this = val; }
935  oo_inline OODictionary( id e1, id e2, ... ) NS_REQUIRES_NIL_TERMINATION {
936  va_list argp; va_start(argp, e2);
937  do
938  (*this)[e1] = ETYPE(e2);
939  while ( (e1 = va_arg( argp, id )) && (e2 = va_arg( argp, id )) );
940  va_end( argp );
941  }
942 
943  ////oo_inline operator int () const { return !*this ? 0 : (int)[get() count]; }
944  oo_inline OOSlice keys() {
945  return [get() allKeys];
946  }
947 
948 #ifdef __clang__
949  oo_inline OODictionary filter( BOOL (^callback)( id key, ETYPE value ) ) {
950  OODictionary out;
951  for( id key in get() ) {
952  ETYPE value = (*this)[key];
953  if ( callback( key, value ) )
954  out[key] = value;
955  }
956  return out;
957  }
958 
959  oo_inline OODictionary map( id (^callback)( id key, ETYPE value ) ) {
960  OODictionary out;
961  for( id key in get() ) {
962  ETYPE value = (*this)[key];
963  out[key] = callback( key, value );
964  }
965  return out;
966  }
967 
968  oo_inline OODictionary operator & ( BOOL (^callback)( id object ) ) {
969  return filter( callback );
970  }
971  oo_inline OODictionary operator & ( id (^callback)( id object ) ) {
972  return map( callback );
973  }
974 
975 #ifdef _LIBCPP_STRING
976  oo_inline OODictionary( const std::map<std::string,ETYPE> &map ) { *this = map; }
977  oo_inline OODictionary &operator = ( const std::map<std::string,ETYPE> &map ) {
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;
981  return *this;
982  }
983  oo_inline operator std::map<std::string,ETYPE> () {
984  std::map<std::string,ETYPE> map;
985  for ( NSString *key in get() )
986  map[[key UTF8String]] = (*this)[key];
987  return map;
988  }
989 
990  oo_inline OODictionary( const std::map<std::string,std::string> &map ) { *this = map; }
991  oo_inline OODictionary &operator = ( const std::map<std::string,std::string> &map ) {
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()];
995  return *this;
996  }
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];
1001  return map;
1002  }
1003 #endif
1004 #endif
1005 
1006  oo_inline NSMutableDictionary *operator & () const { return autoget(); }
1007  ///oo_inline operator int () const { return !*this ? 0 : (int)[[get() allKeys] count]; }
1008 
1009  oo_inline OODictionary &operator = ( id val ) { set( val ); return *this; }
1010  oo_inline OODictionary &operator = ( NSMutableDictionary *val ) { set( val ); return *this; }
1011  oo_inline OODictionary &operator = ( NSDictionary *val ) { OOCopyImmutable( (NSMutableDictionary *)val ); return *this; }
1012  oo_inline OODictionary &operator = ( int nilOrCapacity ) { set( nilOrCapacity ); return *this; }
1013  oo_inline OODictionary &operator = ( long nilOrCapacity ) { set( nilOrCapacity ); return *this; }
1014  oo_inline OODictionary &operator = ( const OODictionary &val ) { set( val.get() ); return *this; }
1015  oo_inline OODictionary &operator = ( const OOArraySub<ETYPE> &val ) { set( val.get() ); return *this; }
1016  oo_inline OODictionary &operator = ( const OODictionarySub<ETYPE> &val ) { set( val.get() ); return *this; }
1017  oo_inline OODictionary &operator = ( const OOReference<NSMutableDictionary *> &val ) { set( val.get() ); return *this; }
1019 
1021  OOArray<id> keys = val;
1022  OOArray<ETYPE> values = val;
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]; /////
1027 #else
1028  (*this)[[*keys objectAtIndex:i]] = *values[i+1]; /////
1029 #endif
1030  return *this;
1031  }
1032  oo_inline OODictionary &operator = ( const char *val );
1033  oo_inline OODictionary &operator = ( const char **val );
1034 
1035  oo_inline BOOL operator == ( NSDictionary *val ) const { return [get() isEqualToDictionary:val]; }
1036  oo_inline BOOL operator != ( NSDictionary *val ) const { return !operator == ( val ); }
1037  oo_inline BOOL operator == ( NSMutableDictionary *val ) const { return [get() isEqualToDictionary:val]; }
1038  oo_inline BOOL operator != ( NSMutableDictionary *val ) const { return !operator == ( val ); }
1039  oo_inline BOOL operator == ( const OODictionary &val ) const { return [get() isEqualToDictionary:val]; }
1040  oo_inline BOOL operator != ( const OODictionary &val ) const { return !operator == ( val ); }
1041 
1042  // dctionary operations
1043  oo_inline OODictionary &operator -= ( id val ) {
1044  [alloc() removeObjectForKey:val];
1045  return *this;
1046  }
1048  [alloc() removeObjectsForKeys:val];
1049  return *this;
1050  }
1052  [alloc() removeObjectsForKeys:[val allKeys]];
1053  return *this;
1054  }
1055  oo_inline OODictionary &operator *= ( const OODictionary<ETYPE> &val ) {
1056  OOArray<id> keys = [get() allKeys];
1057  for ( int i=0 ; i<keys ; i++ ) {
1058  id key = [keys objectAtIndex:i];
1059  (*this)[key] *= val[key];
1060  }
1061  return *this;
1062  }
1063 
1064  oo_inline OODictionary &operator &= ( const OODictionary &val ) {
1065 #if OO_WAS_COMPILER_CRASH
1066  for ( id key in [get() allKeys] )
1067  if ( !val[key] )
1068  *this -= key;
1069  return *this;
1070 #else
1071  OOArray<id> keys = [get() allKeys];
1072  for ( int i=0 ; i<keys ; i++ ) {
1073  id key = [keys objectAtIndex:i];
1074  if ( !val[key] )
1075  *this -= key;
1076  }
1077  return *this;
1078 #endif
1079  }
1081  OOArray<id> keys = [val.get() allKeys];
1082  for ( int i=0 ; i<keys ; i++ ) {
1083  id key = [keys objectAtIndex:i];
1084  if ( !(*this)[key] )
1085  (*this)[key] = val[key];
1086  }
1087  return *this;
1088  }
1089 
1091  OODictionary out; out <<= noalloc(); return out &= val;
1092  }
1094  OODictionary out; out <<= noalloc(); return out |= val;
1095  }
1096 
1097  oo_inline OODictionarySub<ETYPE> operator [] ( id sub ) const {
1098  return OODictionarySub<ETYPE>( this, sub );
1099  }
1100  oo_inline OODictionarySub<ETYPE> operator [] ( NSString *sub ) const {
1101  return OODictionarySub<ETYPE>( this, sub );
1102  }
1103  oo_inline OODictionarySub<ETYPE> operator [] ( cOOString sub ) const;
1104  oo_inline OODictionarySub<ETYPE> operator [] ( const OOArraySub<id> &sub ) const {
1105  return OODictionarySub<ETYPE>( this, sub );
1106  }
1107  oo_inline OODictionarySub<ETYPE> operator [] ( const OOArraySub<OOString> &sub ) const;
1108  oo_inline OODictionarySub<ETYPE> operator [] ( const OODictionarySub<OOString> &sub ) const;
1109 
1110  oo_inline OODictionarySlice<ETYPE> operator [] ( const OOReference<NSMutableArray *> &subs ) const {
1111  return OODictionarySlice<ETYPE>( this, subs.get() );
1112  }
1113 };
1114 
1115 /**
1116  Internal abstract superclass for subscripting operations by operator []
1117  */
1118 
1119 template <typename ETYPE,typename RTYPE,typename STYPE>
1120 class OOSubscript {
1121  friend class OONodeSub;
1122 
1123 protected:
1124  // for x = int, NSString *, NSRange, OOArray<id>
1125  const OOReference<RTYPE *> *root; // for simple var[x]
1126  OOArraySub<RTYPE *> *aref; // for var...[0][x]
1127  OODictionarySub<RTYPE *> *dref; // for var...[@"KEY"][x]
1129 
1131  root = NULL; aref = NULL; dref = NULL;
1132  parentCache = nil;
1133  references = 0;
1134  }
1136  if ( aref && --aref->references == 0 )
1137  delete aref;
1138  if ( dref && --dref->references == 0 )
1139  delete dref;
1140  }
1141 
1143  return OO_AUTORELEASE( OO_RETAIN( get() ) );
1144  }
1145 
1146  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS { return nil; }
1147  oo_inline virtual id set( id val ) const OO_RETURNS { return nil; }
1148 
1149 public:
1151 
1152  oo_inline id alloc( Class c ) const OO_RETURNS {
1153  OO_STRONG id parent = get( NO );
1154  if ( !parent ) {
1155  parent = [[c alloc] init];
1156  OOTrace( @"%p %s %@", this, "VIVIFY", parent );
1157  OO_RELEASE( set( parent ) );
1158  }
1159 #if 001
1160  else if ( ![parent isKindOfClass:c] ) {
1161  OOWarn( @"Reset: %@ == %@", [parent class], c );
1162  OO_RELEASE( set( parent = [parent mutableCopy] ) );
1163  }
1164 #endif
1165  return parent;
1166  }
1167 
1168  RTYPE *parent( BOOL allocate ) const OO_RETURNS {
1169  if ( !parentCache )
1170  ((OOSubscript *)this)->parentCache =
1171  allocate ?
1172  root ? ((OOReference<RTYPE *> *)root)->alloc() : aref ?
1173  aref->alloc( [RTYPE class] ) : dref->alloc( [RTYPE class] )
1174  :
1175  root ? root->get() : aref ? aref->get( NO ) : dref->get( NO );
1176  return parentCache;
1177  }
1178 
1180  return get();
1181  }
1182  oo_inline OODict<ETYPE> dict() {
1183  return get();
1184  }
1185  oo_inline NSUInteger count() {
1186  return [get() count];
1187  }
1188  oo_inline OOSlice keys() {
1189  return [get() allKeys];;
1190  }
1191 
1192  // unaries
1193  oo_inline ETYPE operator * () const OO_RETURNS { return get(); }
1194  oo_inline ETYPE operator -> () const OO_RETURNS { return get(); }
1195  oo_inline id operator & () const OO_AUTORETURNS { return autoget(); }
1196  oo_inline BOOL operator ! () const { return !get( NO ) || get( NO ) == (id)kCFNull; }
1197 
1198  oo_inline operator const char * () const { return [get() UTF8String]; }
1199  ///oo_inline operator NSArray * () const { return get(); }
1200  ///oo_inline operator NSString * () const { return get(); }
1201  ///oo_inline operator BOOL () const { return !!*this; }
1202 
1203  // recursive subscripting
1204  oo_inline OOArraySub<STYPE> operator [] ( int sub ) const {
1205  return OOArraySub<STYPE>( (OODictionarySub<NSMutableArray *> *)this, sub );
1206  }
1207  oo_inline OOArraySlice<STYPE> operator [] ( const NSRange &sub ) const {
1208  return OOArraySlice<STYPE>( (OODictionarySub<NSMutableArray *> *)this, sub );
1209  }
1210  oo_inline OODictionarySub<STYPE> operator [] ( id sub ) const {
1211  return OODictionarySub<STYPE>( (OODictionarySub<NSMutableDictionary *> *)this, sub );
1212  }
1213  oo_inline OODictionarySub<STYPE> operator [] ( const CFStringRef sub ) const {
1214  return (*this)[OO_BRIDGE(id)sub];
1215  }
1216  oo_inline OODictionarySub<STYPE> operator [] ( cOOString sub ) const;
1217  oo_inline OODictionarySub<STYPE> operator [] ( const char *sub ) const;
1218  oo_inline OODictionarySlice<STYPE> operator [] ( const OOReference<NSMutableArray *> &sub ) const {
1219  return OODictionarySlice<STYPE>( (OODictionarySub<NSMutableDictionary *> *)this, sub );
1220  }
1221 
1222  // asignment
1223  oo_inline OOSubscript &operator <<= ( id<NSMutableCopying> val ) {
1224  OO_RELEASE( set( [val mutableCopyWithZone:NULL] ) );
1225  return *this;
1226  }
1227  oo_inline OOSubscript &operator <<= ( const char *val );
1228 
1229  oo_inline OOSubscript &operator = ( NSArray *val ) { set( val ); return *this; }
1230  oo_inline OOSubscript &operator = ( NSDictionary *val ) { set( val ); return *this; }
1231  oo_inline OOSubscript &operator = ( NSMutableString *val ) { set( val ); return *this; }
1232  //oo_inline OOSubscript &operator = ( const char *val ) { *this <<= val; return *this; }
1233  oo_inline OOSubscript &operator = ( NSString *val ) { *this <<= val; return *this; }
1234  oo_inline OOSubscript &operator = ( NSNumber *val ) { set( val ); return *this; }
1235  oo_inline OOSubscript &operator = ( NSNull *val ) { set( val ); return *this; }
1236 
1237  // comparison
1238  oo_inline BOOL operator == ( const ETYPE val ) const { return **this == val; }
1239  oo_inline BOOL operator != ( const ETYPE val ) const { return **this != val; }
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; }
1244 
1245  oo_inline BOOL operator == ( const char *val ) const { return **this == ETYPE( val ); }
1246  oo_inline BOOL operator != ( const char *val ) const { return **this != ETYPE( 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 ); }
1251 
1252  oo_inline BOOL operator == ( const OOSubscript &val ) const { return **this == *val; }
1253  oo_inline BOOL operator != ( const OOSubscript &val ) const { return **this != *val; }
1254  oo_inline BOOL operator >= ( const OOSubscript &val ) const { return **this >= *val; }
1255  oo_inline BOOL operator <= ( const OOSubscript &val ) const { return **this <= *val; }
1256  oo_inline BOOL operator > ( const OOSubscript &val ) const { return **this > *val; }
1257  oo_inline BOOL operator < ( const OOSubscript &val ) const { return **this < *val; }
1258 
1259  // inplace operators
1260  oo_inline OOSubscript &operator += ( const ETYPE val ) { return *this = **this + val; }
1261  oo_inline OOSubscript &operator -= ( const ETYPE val ) { return *this = **this - val; }
1262  oo_inline OOSubscript &operator *= ( const ETYPE val ) { return *this = **this * val; }
1263  oo_inline OOSubscript &operator /= ( const ETYPE val ) { return *this = **this / val; }
1264  oo_inline OOSubscript &operator %= ( const ETYPE val ) { return *this = **this % val; }
1265  oo_inline OOSubscript &operator &= ( const ETYPE val ) { return *this = **this & val; }
1266  oo_inline OOSubscript &operator |= ( const ETYPE val ) { return *this = **this | val; }
1267 
1268  // binary operators
1269  oo_inline ETYPE operator + ( const ETYPE val ) const { return **this + val; }
1270  oo_inline ETYPE operator - ( const ETYPE val ) const { return **this - val; }
1271  oo_inline ETYPE operator * ( const ETYPE val ) const { return **this * val; }
1272  oo_inline ETYPE operator / ( const ETYPE val ) const { return **this / val; }
1273  oo_inline ETYPE operator % ( const ETYPE val ) const { return **this % val; }
1274  oo_inline ETYPE operator & ( const ETYPE val ) const { return **this & val; }
1275  oo_inline ETYPE operator | ( const ETYPE val ) const { return **this | val; }
1276 
1277  // concatenate others
1278  oo_inline ETYPE operator + ( NSString *val ) { return **this + val; }
1279 #if 0000
1280  oo_inline ETYPE operator + ( const char *val ) { return **this + val; }
1281  oo_inline ETYPE operator + ( double val ) { return **this + val; }
1282  oo_inline ETYPE operator + ( int val ) { return **this + val; }
1283  oo_inline ETYPE operator + ( id val ) { return **this + val; }
1284 #endif
1285 };
1286 
1287 /**
1288  Internal class to represent a subscript operation in an expression so it can
1289  be assigned to. You can also use the ~val[i] operation to remove the value
1290  from the array and return it with either expression or autorelease scope.
1291  If the index assigned to is beyond the end of the array it will be padded
1292  with kCFNull values to allow for sparse arrays.
1293 
1294  Usage:
1295 <pre>
1296  - (AVAudioPlayer *)play:OOArray<AVAudioPlayer *> &amp;sounds {
1297  [*sounds[0] play]; // use * operator to get actual object ref
1298  return &amp;~sounds[0]; // delete item at index 0 and return pointer
1299  }
1300 </pre>
1301  */
1302 
1303 template <typename ETYPE>
1304 class OOArraySub : public OOSubscript<ETYPE,NSMutableArray,ETYPE> {
1305  friend class OOArray<ETYPE>;
1306  friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1307  friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1308  friend class OOSubscript<OOArray<ETYPE>,NSMutableArray,ETYPE>;
1309  friend class OOSubscript<OOArray<ETYPE>,NSMutableDictionary,ETYPE>;
1310  friend class OONodeArraySub;
1311  friend class OONodeSub;
1312 
1313  NSInteger idx;
1314 
1315  oo_inline void setIdx( NSInteger sub ) {
1316  idx = sub < 0 ? [this->parent( NO ) count]+sub : sub;
1317  }
1318 protected:
1319  oo_inline OOArraySub( const OOArray<ETYPE> *ref, NSInteger sub ) {
1320  this->root = ref; setIdx( sub );
1321  }
1322  oo_inline OOArraySub( OOArraySub<NSMutableArray *> *ref, NSInteger sub ) {
1323  this->aref = ref; setIdx( sub );
1324  }
1325  oo_inline OOArraySub( OODictionarySub<NSMutableArray *> *ref, NSInteger sub ) {
1326  this->dref = ref; setIdx( sub );
1327  }
1328 
1329 public:
1330  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS {
1331  NSMutableArray *arr = this->parent( NO );
1332  id ret = nil;
1333  if ( arr == (id)kCFNull )
1334  return nil;
1335  if ( idx < 0 )
1336  OOWarn( @"%p Excess negative index (%ld) beyond size of array (%ld)",
1337  this, (OOLong)idx-[arr count], (OOLong)[arr count] );
1338  else if ( idx < [arr count] )
1339  ret = [arr objectAtIndex:idx];
1340  else if ( idx == NSNotFound )
1341  ;
1342  else if ( warn )
1343  OOWarn( @"%p Array ref (%ld) beyond end of array (%ld)",
1344  this, (OOLong)idx, (OOLong)[arr count] );
1345  return ret != (id)kCFNull ? ret : nil;
1346  }
1347  oo_inline virtual id set ( id val ) const OO_RETURNS {
1348  NSMutableArray *arr = this->parent( YES );
1349  NSUInteger count = [arr count];
1350  if ( val == nil )
1351  val = OONoValue;
1352  if ( idx < 0 )
1353  OOWarn( @"%p Excess negative index (%ld) beyond size of array (%ld)",
1354  this, (OOLong)idx-[arr count], (OOLong)[arr count] );
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]; // padding for sparse arrays
1360  [arr addObject:val];
1361  }
1362  return val;
1363  }
1364 
1365  oo_inline operator ETYPE () const /*OO_RETURNS*/ { return get(); }
1366  oo_inline operator NSUInteger () const { return idx; } ///
1367  //oo_inline operator NSString * () const { return get(); } ///
1368  //oo_inline operator NSArray * () const { return get(); } ///
1369  //// oo_inline operator id () const { return get(); } ///
1370 
1371  // assign and assign by mutable copy
1372  oo_inline OOArraySub &operator = ( ETYPE val );// { set( val ); return *this; }
1373  oo_inline OOArraySub &operator = ( const char *val );/* { *this = OOString(val).get(); return *this; }*/
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; }
1378  oo_inline OOArraySub &operator = ( const OOReference<NSMutableArray *> &val ) { set( val.get() ); return *this; }
1379  oo_inline OOArraySub &operator = ( const OOReference<NSMutableDictionary *> &val ) { set( val.get() ); return *this; }
1380 
1381  // delete element and return it
1382  oo_inline ETYPE operator ~ () OO_RETURNS {
1383  ETYPE save = get( NO );
1384 #ifndef OO_ARC
1385  const char *enc = @encode(ETYPE);
1386  if ( enc[0] == '@' )
1387  this->autoget();
1388 #endif
1389  NSMutableArray *arr = this->parent( NO );
1390  if ( 0 <= idx && idx < [arr count] )
1391  [arr removeObjectAtIndex:idx];
1392  else
1393  OOWarn( @"%p Attempt to remove index (%ld) beyond end of array (%ld)",
1394  this, (OOLong)idx, (OOLong)[arr count] );
1395  return save;
1396  }
1397 };
1398 
1399 /**
1400  Internal class representing subscript by key in an expression so it
1401  can be assigned to. Subscripts can be applied recursively "viviifying"
1402  the required Dictionaries (or arrays) at each node as required. Array
1403  and Dictionary acces can be mixed recursively.
1404 
1405  Usage:
1406  <pre>
1407  OODictionary<id> dict;
1408  dict[@"DICT"]["KEY"] <<= @"TEXT1";
1409  dict[@"ARRAY"][0] = <<= @"TEXT2";
1410  </pre>
1411  */
1412 
1413 template <typename ETYPE>
1414 class OODictionarySub : public OOSubscript<ETYPE,NSMutableDictionary,ETYPE> {
1415  friend class OODictionary<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;
1421  friend class OONode;
1422 
1423  OOReference<id> key;
1424 
1425 protected:
1426  oo_inline OODictionarySub( const OOReference<NSMutableDictionary *> *ref, id sub ) {
1427  this->root = ref; this->key = sub;
1428  }
1429  oo_inline OODictionarySub( OOArraySub<NSMutableDictionary *> *ref, id sub ) {
1430  this->aref = ref; this->key = sub;
1431  }
1432  oo_inline OODictionarySub( OODictionarySub<NSMutableDictionary *> *ref, id sub ) {
1433  this->dref = ref; this->key = sub;
1434  }
1435 
1436 public:
1437  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS {
1438  if ( !this->key ) {
1439  OOWarn( @"%p OODictionary get with nil key", this );
1440  return nil;
1441  }
1442  id parent = this->parent( NO ),
1443  value = parent != (id)kCFNull ? [parent objectForKey:this->key] : nil;
1444  return value != (id)kCFNull || 0 ? value : nil;
1445  }
1446  oo_inline virtual id set( id val ) const OO_RETURNS {
1447  if ( !this->key ) {
1448  OOWarn( @"%p OODictionary set with nil key", this );
1449  return val;
1450  }
1451  if ( val == nil )
1452  val = OONoValue;
1453  [this->parent( YES ) setObject:val forKey:this->key];
1454  return val;
1455  }
1456 
1457  oo_inline operator ETYPE () const /*OO_RETURNS*/ { return get(); }
1458 
1459  // assign and assign by mutable copy
1460  oo_inline OODictionarySub &operator = ( ETYPE val );// { set( val ); return *this; }
1461  oo_inline OODictionarySub &operator = ( const char *val );// { *this = OOString(val).get(); return *this; }
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; }
1466  oo_inline OODictionarySub &operator = ( const OOReference<NSMutableArray *> &val ) { set( val.get() ); return *this; }
1467  oo_inline OODictionarySub &operator = ( const OOReference<NSMutableDictionary *> &val ) { set( val.get() ); return *this; }
1468 
1469  // delete entry and return its value
1470  oo_inline ETYPE operator ~ () OO_RETURNS {
1471  ETYPE save = get( NO );
1472 #ifndef OO_ARC
1473  const char *enc = @encode(ETYPE);
1474  if ( enc[0] == '@' )
1475  this->autoget();
1476 #endif
1477  [this->parent( NO ) removeObjectForKey:this->key];
1478  return save;
1479  }
1480 };
1481 
1482 /**
1483  Class representing taking a sub array of objects from an array references a NSRange
1484  and the subscript to the operator []. OORange takes arguments start, end
1485  whereas NSMakeRange takes argument start, length/count. Either can be used.
1486 
1487  Usage:
1488  <pre>
1489  OOStringArray strings = "a b c d";
1490  if ( strings[NSMakeRange(1,2)] == "a b" )
1491  ;// should be true
1492  strings[OORange(1,3)] = OOStringArray( "x y" );
1493  if ( strings == "a x y d" )
1494  ; // should be true
1495  </pre>
1496  */
1497 
1498 template<typename ETYPE>
1499 class OOArraySlice : public OOSubscript<OOArray<ETYPE>,NSMutableArray,ETYPE> {
1500  friend class OOArray<ETYPE>;
1501  friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1502  friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1503  friend class OOSubscript<OOArray<ETYPE>,NSMutableArray,ETYPE>;
1504  friend class OOSubscript<OOArray<ETYPE>,NSMutableDictionary,ETYPE>;
1505 
1506  NSRange slice;
1507 
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)",
1516  this, (OOLong)slice.length, (OOLong)parentCount, (OOLong)slice.location );
1517  slice.length = parentCount-slice.location;
1518  }
1519  }
1520 
1521  oo_inline OOArraySlice( const OOArray<ETYPE> *ref, const NSRange &sub ) {
1522  this->root = ref; setSlice( sub );
1523  }
1524  oo_inline OOArraySlice( OOArraySub<NSMutableArray *> *ref, const NSRange &sub ) {
1525  this->aref = ref; setSlice( sub );
1526  }
1527  oo_inline OOArraySlice( OODictionarySub<NSMutableArray *> *ref, const NSRange &sub ) {
1528  this->dref = ref; setSlice( sub );
1529  }
1530 
1531 public:
1532  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS {
1533  return [this->parent( NO ) subarrayWithRange:slice];
1534  }
1535 
1536  oo_inline OOArray<ETYPE> operator * () const { return get(); }
1537  oo_inline operator NSArray * () const { return get(); }
1538 
1539  oo_inline BOOL operator == ( const OOArray<ETYPE> &in ) const {
1540  return [get() isEqualToArray:in.get()];
1541  }
1542  oo_inline BOOL operator == ( const char *val ) const { return **this == OOArray<ETYPE>( val ); }
1543  oo_inline BOOL operator != ( const char *val ) const { return **this != OOArray<ETYPE>( val ); }
1544 
1545  oo_inline OOArraySlice &operator = ( const OOArray<ETYPE> &in ) {
1546  [this->parent( YES ) replaceObjectsInRange:slice withObjectsFromArray:in];
1547  return *this;
1548  }
1549  oo_inline OOArraySlice &operator = ( const OOArraySlice<ETYPE> &in ) {
1550  return *this = *in;
1551  }
1552  oo_inline OOArraySlice &operator = ( const OODictionarySlice<ETYPE> &in ) {
1553  return *this = *in;
1554  }
1556  OOArray<ETYPE> save = get( NO );
1557  [this->parent( NO ) removeObjectsInRange:slice];
1558  return save;
1559  }
1560 };
1561 
1562 /**
1563  Class representing taking an array of objects from a dictionary references a
1564  "slice" of keys. Can be assigned to.
1565 
1566  Usage:
1567  <pre>
1568  OOStringDict dict = "a 1 b 2 c 3 d 4";
1569  if ( dict[OOSlice("b c")] == "2 3" )
1570  ;// should be true
1571  dict[OOSlice("b c")] = OOStringArray( "9 9" );
1572  if ( dict[OOSlice("b c")] = "9 9" )
1573  ; // should be true
1574  </pre>
1575  */
1576 
1577 template<typename ETYPE>
1578 class OODictionarySlice : public OOSubscript<OOArray<ETYPE>,NSMutableDictionary,ETYPE> {
1579  friend class OODictionary<ETYPE>;
1580  friend class OOSubscript<ETYPE,NSMutableArray,ETYPE>;
1581  friend class OOSubscript<ETYPE,NSMutableDictionary,ETYPE>;
1582 
1583  OOArray<id> slice;
1584 
1585  oo_inline OODictionarySlice( const OODictionary<ETYPE> *ref, NSMutableArray *sub ) {
1586  this->root = ref; slice = sub;
1587  }
1588  oo_inline OODictionarySlice( OOArraySub<NSMutableDictionary *> *ref, NSMutableArray *sub ) {
1589  this->aref = ref; slice = sub;
1590  }
1591  oo_inline OODictionarySlice( OODictionarySub<NSMutableDictionary *> *ref, NSMutableArray *sub ) {
1592  this->dref = ref; slice = sub;
1593  }
1594 public:
1595  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS {
1596  return [this->parent( NO ) objectsForKeys:slice notFoundMarker:(id)kCFNull];
1597  }
1598 
1599  oo_inline OOArray<ETYPE> operator * () const { return get(); }
1600  oo_inline operator NSArray * () const { return get(); }
1601 
1602  oo_inline BOOL operator == ( const OOArray<ETYPE> &in ) const {
1603  return [get() isEqualToArray:in.get()];
1604  }
1605  oo_inline BOOL operator == ( const char *val ) const { return **this == OOArray<ETYPE>( val ); }
1606  oo_inline BOOL operator != ( const char *val ) const { return **this != OOArray<ETYPE>( val ); }
1607 
1608  oo_inline OODictionarySlice &operator = ( const OOArray<ETYPE> &in ) {
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 );
1612  OODictionary<ETYPE> dict = this->parent( YES );
1613  for ( int i=0 ; i<slice ; i++ )
1614  dict[slice[i]] = in[i];
1615  return *this;
1616  }
1617  oo_inline OODictionarySlice &operator = ( const OOArraySlice<ETYPE> &in ) {
1618  return *this = *in;
1619  }
1620  oo_inline OODictionarySlice &operator = ( const OODictionarySlice<ETYPE> &in ) {
1621  return *this = *in;
1622  }
1624  OOArray<ETYPE> save = get( NO );
1625  [this->parent( NO ) removeObjectsForKeys:slice];
1626  return save;
1627  }
1628 };
1629 
1630 #import "objstr.h"
1631 #endif
1632 #endif