Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -1072,10 +1072,14 @@ 4BF8FE571F9A97E100CB9F9C /* OFException+Swift.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8FE541F9A97E100CB9F9C /* OFException+Swift.m */; }; 4BF8FE581F9A97E100CB9F9C /* OFException+Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF8FE551F9A97E100CB9F9C /* OFException+Swift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BF8FE591F9A97E100CB9F9C /* OFException+Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF8FE551F9A97E100CB9F9C /* OFException+Swift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BFC37BD1E50E11C00EE1269 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BFC37BC1E50E11C00EE1269 /* common.h */; }; 4BFC37BE1E50E11C00EE1269 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BFC37BC1E50E11C00EE1269 /* common.h */; }; + 4BFD0B9A1FBA59CB009895D7 /* OFCharacterSet_invertedSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BFD0B981FBA59CB009895D7 /* OFCharacterSet_invertedSet.h */; }; + 4BFD0B9B1FBA59CB009895D7 /* OFCharacterSet_invertedSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BFD0B981FBA59CB009895D7 /* OFCharacterSet_invertedSet.h */; }; + 4BFD0B9C1FBA59CB009895D7 /* OFCharacterSet_invertedSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BFD0B991FBA59CB009895D7 /* OFCharacterSet_invertedSet.m */; }; + 4BFD0B9D1FBA59CB009895D7 /* OFCharacterSet_invertedSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BFD0B991FBA59CB009895D7 /* OFCharacterSet_invertedSet.m */; }; 4BFF3714177E17C100192782 /* OFRemoveItemFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BFF3710177E17C100192782 /* OFRemoveItemFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BFF3715177E17C100192782 /* OFRemoveItemFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BFF3711177E17C100192782 /* OFRemoveItemFailedException.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1783,10 +1787,12 @@ 4BF69CE51BD44F8B00DFFC1B /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = src/platform.h; sourceTree = ""; }; 4BF8FE541F9A97E100CB9F9C /* OFException+Swift.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFException+Swift.m"; path = "src/bridge/OFException+Swift.m"; sourceTree = ""; }; 4BF8FE551F9A97E100CB9F9C /* OFException+Swift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFException+Swift.h"; path = "src/bridge/OFException+Swift.h"; sourceTree = ""; }; 4BFBDD1610A0724800051AFB /* unicode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = unicode.m; path = src/unicode.m; sourceTree = ""; }; 4BFC37BC1E50E11C00EE1269 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = common.h; path = src/encodings/common.h; sourceTree = ""; }; + 4BFD0B981FBA59CB009895D7 /* OFCharacterSet_invertedSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCharacterSet_invertedSet.h; path = src/OFCharacterSet_invertedSet.h; sourceTree = ""; }; + 4BFD0B991FBA59CB009895D7 /* OFCharacterSet_invertedSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFCharacterSet_invertedSet.m; path = src/OFCharacterSet_invertedSet.m; sourceTree = ""; }; 4BFF3710177E17C100192782 /* OFRemoveItemFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFRemoveItemFailedException.h; path = src/exceptions/OFRemoveItemFailedException.h; sourceTree = ""; }; 4BFF3711177E17C100192782 /* OFRemoveItemFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFRemoveItemFailedException.m; path = src/exceptions/OFRemoveItemFailedException.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2149,10 +2155,12 @@ 4BD86D811237A6C600ED9912 /* OFBlock.m */, 4BB99CD91FAEC9DA00CC79A9 /* OFCharacterSet.h */, 4BB99CD61FAEC9D900CC79A9 /* OFCharacterSet.m */, 4BB99CD71FAEC9D900CC79A9 /* OFCharacterSet_bitset.h */, 4BB99CD81FAEC9DA00CC79A9 /* OFCharacterSet_bitset.m */, + 4BFD0B981FBA59CB009895D7 /* OFCharacterSet_invertedSet.h */, + 4BFD0B991FBA59CB009895D7 /* OFCharacterSet_invertedSet.m */, 4BB99CE21FAF542000CC79A9 /* OFCharacterSet_range.h */, 4BB99CE31FAF542000CC79A9 /* OFCharacterSet_range.m */, 4BAF5F46123460C900F4E111 /* OFCollection.h */, 4B6743F7163C395900EB1E59 /* OFCondition.h */, 4B6743F8163C395900EB1E59 /* OFCondition.m */, @@ -2786,10 +2794,11 @@ 4B2C228E1DA292BE00735907 /* OFArray_adjacent.h in Headers */, 4B2C228F1DA292BE00735907 /* OFArray_adjacentSubarray.h in Headers */, 4B2C21D91DA292BE00735907 /* OFArray_subarray.h in Headers */, 4B2C22901DA292BE00735907 /* OFAutoreleasePool+Private.h in Headers */, 4BB99CDD1FAEC9DA00CC79A9 /* OFCharacterSet_bitset.h in Headers */, + 4BFD0B9B1FBA59CB009895D7 /* OFCharacterSet_invertedSet.h in Headers */, 4BB99CE51FAF542000CC79A9 /* OFCharacterSet_range.h in Headers */, 4B2C22911DA292BE00735907 /* OFCountedSet_hashtable.h in Headers */, 4B1223171F23E6C100D9F8FF /* OFData+Private.h in Headers */, 4B2C22921DA292BE00735907 /* OFDictionary_hashtable.h in Headers */, 4B2C22931DA292BE00735907 /* OFINICategory+Private.h in Headers */, @@ -3024,10 +3033,11 @@ 4B2B3E7D140D430500EC2F7C /* OFArray_adjacent.h in Headers */, 4B9BB7BD141CDE2D000AD1CC /* OFArray_adjacentSubarray.h in Headers */, 4B9BB7BF141CDE2D000AD1CC /* OFArray_subarray.h in Headers */, 4B1473CB17E6391900B46BB8 /* OFAutoreleasePool+Private.h in Headers */, 4BB99CDC1FAEC9DA00CC79A9 /* OFCharacterSet_bitset.h in Headers */, + 4BFD0B9A1FBA59CB009895D7 /* OFCharacterSet_invertedSet.h in Headers */, 4BB99CE41FAF542000CC79A9 /* OFCharacterSet_range.h in Headers */, 4BA85BCA140ECCE800E91D51 /* OFCountedSet_hashtable.h in Headers */, 4B1223141F23E6C000D9F8FF /* OFData+Private.h in Headers */, 4B2B3E7F140D430500EC2F7C /* OFDictionary_hashtable.h in Headers */, 4B06855518B2AD3800FC731A /* OFINICategory+Private.h in Headers */, @@ -3391,10 +3401,11 @@ 4B2C21231DA292BE00735907 /* OFArray_subarray.m in Sources */, 4B2C21241DA292BE00735907 /* OFAutoreleasePool.m in Sources */, 4B2C21261DA292BE00735907 /* OFBlock.m in Sources */, 4BB99CDB1FAEC9DA00CC79A9 /* OFCharacterSet.m in Sources */, 4BB99CDF1FAEC9DA00CC79A9 /* OFCharacterSet_bitset.m in Sources */, + 4BFD0B9D1FBA59CB009895D7 /* OFCharacterSet_invertedSet.m in Sources */, 4BB99CE71FAF542000CC79A9 /* OFCharacterSet_range.m in Sources */, 4B2C21271DA292BE00735907 /* OFCondition.m in Sources */, 4B2C21281DA292BE00735907 /* OFConstantString.m in Sources */, 4B2C21291DA292BE00735907 /* OFCountedSet.m in Sources */, 4B2C212A1DA292BE00735907 /* OFCountedSet_hashtable.m in Sources */, @@ -3603,10 +3614,11 @@ 4B9BB7C0141CDE2D000AD1CC /* OFArray_subarray.m in Sources */, 4B3D238D1337FC0D00DD29B8 /* OFAutoreleasePool.m in Sources */, 4B3D238E1337FC0D00DD29B8 /* OFBlock.m in Sources */, 4BB99CDA1FAEC9DA00CC79A9 /* OFCharacterSet.m in Sources */, 4BB99CDE1FAEC9DA00CC79A9 /* OFCharacterSet_bitset.m in Sources */, + 4BFD0B9C1FBA59CB009895D7 /* OFCharacterSet_invertedSet.m in Sources */, 4BB99CE61FAF542000CC79A9 /* OFCharacterSet_range.m in Sources */, 4B674401163C395900EB1E59 /* OFCondition.m in Sources */, 4B3D238F1337FC0D00DD29B8 /* OFConstantString.m in Sources */, 4B45355413DCFE1E0037AB4D /* OFCountedSet.m in Sources */, 4BA85BCB140ECCE800E91D51 /* OFCountedSet_hashtable.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -159,10 +159,11 @@ SRCS += OFArray_adjacent.m \ OFArray_adjacentSubarray.m \ OFArray_subarray.m \ OFCharacterSet_bitset.m \ + OFCharacterSet_invertedSet.m \ OFCharacterSet_range.m \ OFCountedSet_hashtable.m \ OFDictionary_hashtable.m \ OFMutableArray_adjacent.m \ OFMutableDictionary_hashtable.m \ Index: src/OFCharacterSet.h ================================================================== --- src/OFCharacterSet.h +++ src/OFCharacterSet.h @@ -23,10 +23,16 @@ * @class OFCharacterSet OFCharacterSet.h ObjFW/OFCharacterSet.h * * @brief A class cluster representing a character set. */ @interface OFCharacterSet: OFObject +/*! + * The inverted set, containing only the characters that do not exist in the + * receiver. + */ +@property (readonly, nonatomic) OFCharacterSet *invertedSet; + /*! * @brief Creates a new character set containing the characters of the * specified string. * * @param characters The characters for the character set Index: src/OFCharacterSet.m ================================================================== --- src/OFCharacterSet.m +++ src/OFCharacterSet.m @@ -16,10 +16,11 @@ #include "config.h" #import "OFCharacterSet.h" #import "OFCharacterSet_bitset.h" +#import "OFCharacterSet_invertedSet.h" #import "OFCharacterSet_range.h" static struct { Class isa; } placeholder; @@ -120,6 +121,12 @@ - (bool)characterIsMember: (of_unichar_t)character { OF_UNRECOGNIZED_SELECTOR } + +- (OFCharacterSet *)invertedSet +{ + return [[[OFCharacterSet_invertedSet alloc] + of_initWithCharacterSet: self] autorelease]; +} @end ADDED src/OFCharacterSet_invertedSet.h Index: src/OFCharacterSet_invertedSet.h ================================================================== --- src/OFCharacterSet_invertedSet.h +++ src/OFCharacterSet_invertedSet.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFCharacterSet.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFCharacterSet_invertedSet: OFCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, of_unichar_t); +} + +- (instancetype)of_initWithCharacterSet: (OFCharacterSet *)characterSet + OF_METHOD_FAMILY(init); +@end + +OF_ASSUME_NONNULL_END ADDED src/OFCharacterSet_invertedSet.m Index: src/OFCharacterSet_invertedSet.m ================================================================== --- src/OFCharacterSet_invertedSet.m +++ src/OFCharacterSet_invertedSet.m @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFCharacterSet_invertedSet.h" +#import "OFString.h" + +#import "OFOutOfRangeException.h" + +@implementation OFCharacterSet_invertedSet +- (instancetype)of_initWithCharacterSet: (OFCharacterSet *)characterSet +{ + self = [super init]; + + _characterSet = [characterSet retain]; + _characterIsMember = (bool (*)(id, SEL, of_unichar_t)) + [_characterSet methodForSelector: @selector(characterIsMember:)]; + + return self; +} + +- (void)dealloc +{ + [_characterSet release]; + + [super dealloc]; +} + +- (bool)characterIsMember: (of_unichar_t)character +{ + return !_characterIsMember(_characterSet, @selector(characterIsMember:), + character); +} + +- (OFCharacterSet *)invertedSet +{ + return [[_characterSet retain] autorelease]; +} +@end Index: tests/OFCharacterSetTests.m ================================================================== --- tests/OFCharacterSetTests.m +++ tests/OFCharacterSetTests.m @@ -37,11 +37,11 @@ @implementation TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFCharacterSet *cs; + OFCharacterSet *cs, *ics; bool ok; module = @"OFCharacterSet"; cs = [[[SimpleCharacterSet alloc] init] autorelease]; @@ -87,8 +87,22 @@ } else if ([cs characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); + ok = true; + ics = [cs invertedSet]; + for (of_unichar_t c = 0; c < 65536; c++) { + if (c >= '0' && c <= '9') { + if ([ics characterIsMember: c]) + ok = false; + } else if (![ics characterIsMember: c]) + ok = false; + } + TEST(@"-[invertedSet]", ok); + + TEST(@"Inverting -[invertedSet] returns original set", + [ics invertedSet] == cs) + [pool drain]; } @end