Files
textmate/Shared/include/oak/CocoaSTL.h
Allan Odgaard 9894969e67 Initial commit
2012-08-09 16:25:56 +02:00

538 lines
23 KiB
Objective-C

#ifndef OAK_COCOASTL_H_MGEOT7R7
#define OAK_COCOASTL_H_MGEOT7R7
#import "misc.h"
#import "iterator_macros.h"
#import <text/utf8.h>
@interface NSObject (compare)
- (NSComparisonResult)compare:(NSObject*)otherObject;
@end
struct OakArrayIteratorRef; // forward declaration
/* =================================== */
/* = Reference counted memory buffer = */
/* = This is a private class! = */
/* =================================== */
template <typename T> void OakDeleteArray (T* array) { delete[] array; }
template <typename T> void OakDeleteObject (T* object) { delete object; }
template <typename T, void(*F)(T*) = OakDeleteArray>
struct OakSharedBuffer
{
struct impl
{
impl () : M_retainCount(1) { M_buffer = NULL; }
~impl () { F(M_buffer); }
T* M_buffer;
size_t M_retainCount;
};
typedef OakSharedBuffer self;
mutable impl* M_pimpl;
void retain () { ++M_pimpl->M_retainCount; }
void release () { if(M_pimpl && --M_pimpl->M_retainCount == 0) delete M_pimpl; }
size_t retain_count () const { return M_pimpl ? M_pimpl->M_retainCount : 1; }
impl* get_pimpl () const { if(M_pimpl == NULL) M_pimpl = new impl(); return M_pimpl; }
OakSharedBuffer () { M_pimpl = NULL; }
OakSharedBuffer (T* buf) { M_pimpl = NULL; set(buf); }
OakSharedBuffer (self const& rhs) { M_pimpl = rhs.get_pimpl(); retain(); }
~OakSharedBuffer () { release(); }
self& operator= (self const& rhs) { if(this != &rhs) { this->~self(); new (this) self(rhs); } return *this; }
T* get () const { return M_pimpl ? M_pimpl->M_buffer : NULL; }
void set (T* buf) { if(M_pimpl) F(M_pimpl->M_buffer); get_pimpl()->M_buffer = buf; }
T& operator* () { assert(M_pimpl); assert(M_pimpl->M_buffer); return *M_pimpl->M_buffer; }
T& operator[] (int i) { assert(M_pimpl); assert(M_pimpl->M_buffer); return M_pimpl->M_buffer[i]; }
T* operator-> () { assert(M_pimpl); assert(M_pimpl->M_buffer); return M_pimpl->M_buffer; }
};
/* ============================ */
/* = operator<< for NSObjects = */
/* ============================ */
namespace std
{
template <typename _CharT, typename _Traits>
basic_ostream<_CharT, _Traits>& operator<< (basic_ostream<_CharT, _Traits>& out, id obj)
{
return out << ([[obj description] UTF8String] ?: "<nil>");
}
};
/* ============================= */
/* = Objective-C smart pointer = */
/* ============================= */
template <typename T = NSObject*>
struct objc_ptr
{
typedef objc_ptr self;
T M_object;
objc_ptr () : M_object(nil) { reset(nil); }
objc_ptr (T object) : M_object(nil) { reset(object); }
objc_ptr (self const& rhs) : M_object(nil) { reset(rhs); }
objc_ptr (OakArrayIteratorRef const& ref);
~objc_ptr () { reset(nil); }
self& operator= (self const& rhs) { reset(rhs); return *this; }
self& operator= (T object) { reset(object); return *this; }
operator T () const { return M_object; }
T get () const { return M_object; }
T operator-> () const { return M_object; }
bool operator== (T rhs) const { return (M_object == rhs) || [M_object isEqual:rhs] == YES; }
bool operator!= (T rhs) const { return !(*this == rhs); }
bool operator< (T rhs) const { return [M_object compare:rhs] == NSOrderedAscending; }
bool operator> (T rhs) const { return !(*this < rhs); }
bool operator<= (T rhs) const { return *this == rhs || *this < rhs; }
bool operator>= (T rhs) const { return *this == rhs || !(*this < rhs); }
void reset (T object)
{
if(M_object != object)
{
[M_object release];
M_object = object ? [object retain] : nil;
}
}
};
/* ========================= */
/* = back_inserter support = */
/* ========================= */
template <typename C, typename T, int N, typename S>
struct OakGenericInsert : public S
{
typedef OakGenericInsert self;
objc_ptr<C> M_container;
struct buffer_node { T mem[N]; size_t cur; };
OakSharedBuffer<buffer_node, OakDeleteObject> M_buf;
OakGenericInsert (C container) : M_container(container), M_buf(new buffer_node) { M_buf->cur = 0; }
~OakGenericInsert () { if(M_buf.retain_count() == 1) this->overflow(M_container.get(), M_buf->mem, M_buf->cur); }
void insert (T value)
{
if(M_buf->cur == N)
M_buf->cur = overflow(M_container.get(), M_buf->mem, M_buf->cur);
M_buf->mem[M_buf->cur++] = value;
};
};
template <typename C>
struct OakAddObjectInsert
{
objc_ptr<C> M_container;
OakAddObjectInsert (C container) : M_container(container) { }
void insert (id value) { [M_container.get() addObject:value]; }
};
struct OakInsertInNSIndexSet
{
objc_ptr<NSMutableIndexSet*> M_container;
OakInsertInNSIndexSet (NSMutableIndexSet* indexSet) : M_container(indexSet) { }
size_t insert (NSUInteger i) { [M_container.get() addIndex:i]; return 0; }
};
template <typename T>
struct OakInsertInNSData
{
size_t overflow (NSMutableData* data, T* bytes, size_t len)
{
[data appendBytes:bytes length:sizeof(T) * len];
return 0;
}
};
struct OakInsertInNSString
{
size_t overflow (NSMutableString* str, char* bytes, size_t len)
{
char* last = utf8::find_safe_end(bytes, bytes + len);
CFStringAppendCString((CFMutableStringRef)str, std::string(bytes, last).c_str(), kCFStringEncodingUTF8);
std::copy(last, bytes + len, bytes);
return (bytes + len) - last;
}
};
template <typename C, typename T, typename A>
struct OakGenericInsertIterator : public std::iterator<std::output_iterator_tag, T>, A
{
typedef OakGenericInsertIterator self;
OakGenericInsertIterator (C container) : A(container) { }
C container () const { return A::M_container; }
self& operator++ () { return *this; }
self& operator++ (int) { return *this; }
self& operator* () { return *this; }
self& operator= (T value) { A::insert(value); return *this; }
};
template <typename T> OakGenericInsertIterator<NSMutableData*, T, OakGenericInsert<NSMutableData*, T, 256, OakInsertInNSData<T> > > back_inserter (NSMutableData* data) { return data; }
inline OakGenericInsertIterator<NSMutableData*, char, OakGenericInsert<NSMutableData*, char, 256, OakInsertInNSData<char> > > back_inserter (NSMutableData* data) { return data; }
inline OakGenericInsertIterator<NSMutableString*, char, OakGenericInsert<NSMutableString*, char, 256, OakInsertInNSString> > back_inserter (NSMutableString* str) { return str; }
inline OakGenericInsertIterator<NSMutableArray*, id, OakAddObjectInsert<NSMutableArray*> > back_inserter (NSMutableArray* array) { return array; }
inline OakGenericInsertIterator<NSMutableSet*, id, OakAddObjectInsert<NSMutableSet*> > back_inserter (NSMutableSet* set) { return set; }
inline OakGenericInsertIterator<NSMutableIndexSet*, NSUInteger, OakInsertInNSIndexSet> back_inserter (NSMutableIndexSet* indexSet) { return indexSet; }
/* ============================ */
/* = NSArray iterator support = */
/* ============================ */
struct OakArrayIteratorRef
{
typedef OakArrayIteratorRef self;
objc_ptr<NSArray*> M_array;
NSUInteger M_index;
OakArrayIteratorRef (NSArray* array, NSUInteger index) : M_array(array), M_index(index) { }
NSArray* array () const { return M_array.get(); }
NSMutableArray* mutableArray () const { assert([array() isKindOfClass:[NSMutableArray class]]); return (NSMutableArray*)array(); }
id value () const { return [array() objectAtIndex:M_index]; }
id get () const { return value(); }
operator id () const { return value(); }
operator objc_ptr<id> () const { return value(); }
self& operator= (id object) { [mutableArray() replaceObjectAtIndex:M_index withObject:object]; return *this; }
self& operator= (self const& rhs) { [mutableArray() replaceObjectAtIndex:M_index withObject:rhs]; return *this; }
bool operator== (id rhs) const { return [value() isEqual:rhs] == YES; }
bool operator!= (id rhs) const { return !(*this == rhs); }
bool operator< (id rhs) const { return [(NSObject*)value() compare:rhs] == NSOrderedAscending; }
bool operator> (id rhs) const { return [(NSObject*)value() compare:rhs] == NSOrderedDescending; }
bool operator<= (id rhs) const { return *this == rhs || *this < rhs; }
bool operator>= (id rhs) const { return *this == rhs || *this > rhs; }
};
template <typename T>
objc_ptr<T>::objc_ptr (OakArrayIteratorRef const& ref) : M_object(nil) { reset(ref); }
struct OakArrayIterator : public std::iterator<std::random_access_iterator_tag, objc_ptr<id>, ptrdiff_t, objc_ptr<id>*, OakArrayIteratorRef>
{
typedef OakArrayIterator self;
OakArrayIterator (NSArray* array, NSUInteger index) : M_array(array), M_index(index) { }
self& operator++ () { M_index++; return *this; }
self& operator-- () { M_index--; return *this; }
self operator++ (int) { self tmp(*this); M_index++; return tmp; }
self operator-- (int) { self tmp(*this); M_index--; return tmp; }
self operator+ (int i) const { return self(M_array, M_index + i); }
self operator- (int i) const { return self(M_array, M_index - i); }
self& operator+= (int i) { M_index += i; return *this; }
self& operator-= (int i) { M_index -= i; return *this; }
int operator- (self const& rhs) const { return M_index - rhs.M_index; }
bool operator== (self const& rhs) const { return M_index == rhs.M_index && M_array.get() == rhs.M_array.get(); }
bool operator!= (self const& rhs) const { return !(*this == rhs); }
bool operator< (self const& rhs) const { return M_index < rhs.M_index; }
OakArrayIteratorRef operator* () { return OakArrayIteratorRef(M_array, M_index); }
OakArrayIteratorRef operator[] (int i) { return OakArrayIteratorRef(M_array, M_index + i); }
id operator* () const { return [M_array.get() objectAtIndex:M_index]; }
id operator[] (int i) const { return [M_array.get() objectAtIndex:M_index + i]; }
NSUInteger index () const { return M_index; }
private:
objc_ptr<NSArray*> M_array;
NSUInteger M_index;
};
/* ========================= */
/* = NSDictionary iterator = */
/* ========================= */
struct OakDictionaryIterator : public std::iterator<std::random_access_iterator_tag, std::pair<NSObject*, NSObject*> const>
{
typedef OakDictionaryIterator self;
typedef std::pair<id, id> value_type;
objc_ptr<NSDictionary*> M_dictionary;
size_t M_index, M_count;
mutable value_type M_value;
mutable OakSharedBuffer<NSObject*> M_buffer;
OakDictionaryIterator (NSDictionary* dictionary, size_t index) : M_dictionary(dictionary), M_index(index), M_count([dictionary count]) { }
OakDictionaryIterator (NSDictionary* dictionary, size_t index, OakSharedBuffer<NSObject*> const& buffer) : M_dictionary(dictionary), M_index(index), M_count([dictionary count]), M_buffer(buffer) { }
self& operator++ () { ++M_index; return *this; }
self& operator-- () { --M_index; return *this; }
self operator++ (int) { self tmp(*this); ++M_index; return tmp; }
self operator-- (int) { self tmp(*this); --M_index; return tmp; }
self operator+ (int i) const { return self(M_dictionary, M_index + i, M_buffer); }
self operator- (int i) const { return self(M_dictionary, M_index - i, M_buffer); }
self& operator+= (int i) { M_index += i; return *this; }
self& operator-= (int i) { M_index -= i; return *this; }
int operator- (self const& rhs) const { return M_index - rhs.M_index; }
bool operator== (self const& rhs) const { return M_index == rhs.M_index; }
bool operator!= (self const& rhs) const { return !(*this == rhs); }
bool operator< (self const& rhs) const { return M_index < rhs.M_index; }
void acquire () const
{
if(M_buffer.get() == NULL)
{
id* mem = new id [2*M_count];
CFDictionaryGetKeysAndValues((CFDictionaryRef)M_dictionary.get(), (void const**)mem, (void const**)(mem + M_count));
M_buffer.set(mem);
}
M_value = value_type(M_buffer.get()[M_index], M_buffer.get()[M_index + M_count]);
}
value_type const* operator-> () const { acquire(); return &M_value; }
value_type const& operator* () const { acquire(); return M_value;; }
};
/* ================== */
/* = NSSet iterator = */
/* ================== */
struct OakSetIterator : public std::iterator<std::forward_iterator_tag, id>
{
typedef OakSetIterator self;
objc_ptr<NSSet*> M_set;
objc_ptr<NSEnumerator*> M_enumerator;
objc_ptr<id> M_value;
OakSetIterator (NSSet* set, NSEnumerator* enumerator) : M_set(set), M_enumerator(enumerator) { advance(); }
void advance () { M_value = [M_enumerator.get() nextObject]; }
self& operator++ () { advance(); return *this; }
self operator++ (int) { self tmp(*this); advance(); return tmp; }
bool operator== (self const& rhs) const { return (M_value.get() == nil && rhs.M_value.get() == nil) || (M_set.get() == rhs.M_set.get() && M_value.get() == rhs.M_value.get() && M_enumerator.get() == rhs.M_enumerator.get()); }
bool operator!= (self const& rhs) const { return !(*this == rhs); }
id operator* () const { return M_value; }
};
/* ========================================== */
/* = Generic superclass for iterators which = */
/* = need to copy values from the container = */
/* ========================================== */
template <typename C, typename T, T*(*F)(C)>
struct OakBufferIterator : public std::iterator<std::random_access_iterator_tag, T>
{
typedef OakBufferIterator self;
objc_ptr<C> M_container;
mutable OakSharedBuffer<T> M_buffer;
size_t M_index;
OakBufferIterator () { }
OakBufferIterator (C container, size_t index) : M_container(container), M_index(index) { }
OakBufferIterator (C container, size_t index, OakSharedBuffer<T> const& buffer) : M_container(container), M_buffer(buffer), M_index(index) { }
self& operator++ () { M_index++; return *this; }
self& operator-- () { M_index--; return *this; }
self operator++ (int) { self tmp(*this); M_index++; return tmp; }
self operator-- (int) { self tmp(*this); M_index--; return tmp; }
self operator+ (int i) const { return self(M_container, M_index + i, M_buffer); }
self operator- (int i) const { return self(M_container, M_index - i, M_buffer); }
self& operator+= (int i) { M_index += i; return *this; }
self& operator-= (int i) { M_index -= i; return *this; }
int operator- (self const& rhs) const { return M_index - rhs.M_index; }
bool operator== (self const& rhs) const { return M_index == rhs.M_index && M_container.get() == rhs.M_container.get(); }
bool operator!= (self const& rhs) const { return M_index != rhs.M_index || M_container.get() != rhs.M_container.get(); }
bool operator< (self const& rhs) const { return M_index < rhs.M_index; }
void acquire () const { if(M_buffer.get() == NULL) M_buffer.set(F(M_container)); }
T& operator* () const { acquire(); return M_buffer[M_index]; }
T& operator[] (int i) const { acquire(); return M_buffer[M_index + i]; }
};
inline NSUInteger const* OakIndexSetIteratorInit (NSIndexSet* indexSet)
{
NSUInteger size = [indexSet count];
NSUInteger* res = new NSUInteger[size];
NSRange range = NSMakeRange([indexSet firstIndex], [indexSet lastIndex]-[indexSet firstIndex] + 1);
[indexSet getIndexes:res maxCount:size inIndexRange:&range];
return res;
}
inline unichar* OakStringIteratorInit (NSString* string)
{
unichar* res = new unichar[[string length]];
[string getCharacters:res];
return res;
}
typedef OakBufferIterator<NSIndexSet*, NSUInteger const, OakIndexSetIteratorInit> OakIndexSetIterator;
typedef OakBufferIterator<NSString*, unichar, OakStringIteratorInit> OakStringIterator;
/* =============================================== */
/* = beginof/endof functions to create iterators = */
/* =============================================== */
inline OakArrayIterator beginof (NSArray* anArray) { return OakArrayIterator(anArray, 0); }
inline OakArrayIterator endof (NSArray* anArray) { return OakArrayIterator(anArray, [anArray count]); }
inline OakDictionaryIterator beginof (NSDictionary* aDictionary) { return OakDictionaryIterator(aDictionary, 0); }
inline OakDictionaryIterator endof (NSDictionary* aDictionary) { return OakDictionaryIterator(aDictionary, [aDictionary count]); }
inline OakSetIterator beginof (NSSet* aSet) { return OakSetIterator(aSet, [aSet objectEnumerator]); }
inline OakSetIterator endof (NSSet* aSet) { return OakSetIterator(aSet, nil); }
inline OakIndexSetIterator beginof (NSIndexSet* anIndexSet) { return OakIndexSetIterator(anIndexSet, 0); }
inline OakIndexSetIterator endof (NSIndexSet* anIndexSet) { return OakIndexSetIterator(anIndexSet, [anIndexSet count]); }
inline OakStringIterator beginof (NSString* aString) { return OakStringIterator(aString, 0); }
inline OakStringIterator endof (NSString* aString) { return OakStringIterator(aString, [aString length]); }
template <typename T> T* beginof (NSData* data) { return (T*)[data bytes]; }
template <typename T> T* endof (NSData* data) { return (T*)((char*)[data bytes] + [data length]); }
//template <typename T> T* beginof (NSMutableData* data) { return (T*)[data mutableBytes]; }
//template <typename T> T* endof (NSMutableData* data) { return (T*)((char*)[data mutableBytes] + [data length]); }
inline unsigned char const* beginof (NSData* data) { return beginof<unsigned char const>(data); }
inline unsigned char const* endof (NSData* data) { return endof<unsigned char const>(data); }
//inline unsigned char* beginof (NSMutableData* data) { return beginof<unsigned char>(data); }
//inline unsigned char* endof (NSMutableData* data) { return endof<unsigned char>(data); }
/* ================================================= */
/* = rbeginof/rendof functions to create iterators = */
/* = wrapped in a std::reverse_iterator = */
/* ================================================= */
inline std::reverse_iterator<OakArrayIterator> rbeginof (NSArray* anArray) { return std::reverse_iterator<OakArrayIterator>(endof(anArray)); }
inline std::reverse_iterator<OakArrayIterator> rendof (NSArray* anArray) { return std::reverse_iterator<OakArrayIterator>(beginof(anArray)); }
inline std::reverse_iterator<OakIndexSetIterator> rbeginof (NSIndexSet* anIndexSet) { return std::reverse_iterator<OakIndexSetIterator>(endof(anIndexSet)); }
inline std::reverse_iterator<OakIndexSetIterator> rendof (NSIndexSet* anIndexSet) { return std::reverse_iterator<OakIndexSetIterator>(beginof(anIndexSet)); }
inline std::reverse_iterator<OakStringIterator> rbeginof (NSString* aString) { return std::reverse_iterator<OakStringIterator>(endof(aString)); }
inline std::reverse_iterator<OakStringIterator> rendof (NSString* aString) { return std::reverse_iterator<OakStringIterator>(beginof(aString)); }
template <typename T> std::reverse_iterator<T*> rbeginof (NSData* data) { return std::reverse_iterator<T*>(endof<T>(data)); }
template <typename T> std::reverse_iterator<T*> rendof (NSData* data) { return std::reverse_iterator<T*>(beginof<T>(data)); }
//template <typename T> std::reverse_iterator<T*> rbeginof (NSMutableData* data) { return std::reverse_iterator<T*>(endof<T>(data)); }
//template <typename T> std::reverse_iterator<T*> rendof (NSMutableData* data) { return std::reverse_iterator<T*>(beginof<T>(data)); }
inline std::reverse_iterator<unsigned char const*> rbeginof (NSData* data) { return std::reverse_iterator<unsigned char const*>(endof(data)); }
inline std::reverse_iterator<unsigned char const*> rendof (NSData* data) { return std::reverse_iterator<unsigned char const*>(beginof(data)); }
//inline std::reverse_iterator<unsigned char*> rbeginof (NSMutableData* data) { return std::reverse_iterator<unsigned char*>(endof(data)); }
//inline std::reverse_iterator<unsigned char*> rendof (NSMutableData* data) { return std::reverse_iterator<unsigned char*>(beginof(data)); }
/* ======================================= */
/* = Some functions to create a Cocoa = */
/* = container from an iterator sequence = */
/* ======================================= */
template <typename _InputIter, typename _OutputIter>
_OutputIter decode_utf8 (_InputIter first, _InputIter const& last, _OutputIter res)
{
for(; first != last; ++first)
{
typename std::iterator_traits<_InputIter>::value_type ch = *first;
if(ch < 0x80)
{
*res++ = ch;
}
else
{
size_t numBytes = 1;
while((ch & (1 << (7-numBytes))) && numBytes < 6)
++numBytes;
uint32_t decoded = numBytes == 1 ? 0xFFFD : ch & ((1 << (7-numBytes))-1);
while(--numBytes && ++first != last)
{
if((*first & 0xC0) != 0x80)
{
++numBytes;
--first;
break;
}
decoded = (decoded << 6) | (*first & 0x3F);
}
if(numBytes)
*res++ = 0xFFFD;
else if(decoded < 0x10000)
*res++ = decoded;
else
{
*res++ = 0xD800 - (0x10000 >> 10) + (decoded >> 10);
*res++ = 0xDC00 + (decoded & 0x3FF);
}
if(first == last)
break;
}
}
return res;
}
template <typename _InputIter>
NSString* NSStringFromUTF8Sequence (_InputIter const& first, _InputIter const& last)
{
if(first == last)
return @"";
std::vector<UniChar> v;
decode_utf8(first, last, back_inserter(v));
return [(NSString*)CFStringCreateWithCharacters(kCFAllocatorDefault, &v[0], v.size()) autorelease];
}
template <typename _InputIter>
NSString* NSStringFromUTF16Sequence (_InputIter first, _InputIter last)
{
CFIndex numChars = std::distance(first, last);
UniChar* chars = (UniChar*)CFAllocatorAllocate(kCFAllocatorDefault, sizeof(UniChar) * numChars, 0);
std::copy(first, last, chars);
return [(NSString*)CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, chars, numChars, kCFAllocatorDefault) autorelease];
}
template <typename T, typename _InputIter>
NSData* NSDataFromSequence (_InputIter first, _InputIter last)
{
CFIndex length = std::distance(first, last);
T* bytes = (T*)CFAllocatorAllocate(kCFAllocatorDefault, sizeof(T) * length, 0);
std::copy(first, last, bytes);
return [(NSData*)CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8*)bytes, sizeof(T) * length, kCFAllocatorDefault) autorelease];
}
template <typename _InputIter>
NSArray* NSArrayFromSequence (_InputIter first, _InputIter last)
{
CFIndex length = std::distance(first, last);
NSMutableArray* res = [NSMutableArray arrayWithCapacity:length];
std::copy(first, last, back_inserter(res));
return res;
}
/* ================================== */
/* = Specially for Cocoa containers = */
/* ================================== */
#define enumerate(container,var) for(NSEnumerator* _enumerator = [container objectEnumerator]; var = [_enumerator nextObject]; )
/* ==================================== */
/* = Adaptable Function Objects which = */
/* = wrap for an Objective-C selector = */
/* ==================================== */
template <typename R = id>
struct method : std::unary_function<id, R>
{
SEL M_selector;
method (char const* str) : M_selector(sel_getUid(str)) { }
method (SEL selector) : M_selector(selector) { }
R operator() (id obj) const { return ((R(*)(id, SEL, ...))objc_msgSend)(obj, M_selector); }
};
template <typename A = id, typename R = id>
struct unary_method : std::binary_function<id, A, R>
{
SEL M_selector;
unary_method (char const* str) : M_selector(sel_getUid(str)) { }
unary_method (SEL selector) : M_selector(selector) { }
R operator() (id obj, A arg) const { return ((R(*)(id, SEL, ...))objc_msgSend)(obj, M_selector, arg); }
std::binder1st< unary_method<A, R> > operator() (id obj) const { return std::binder1st< unary_method<A, R> >(*this, obj); }
};
#endif /* end of include guard: OAK_COCOASTL_H_MGEOT7R7 */