diff options
author | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2010-06-09 22:37:37 +0000 |
---|---|---|
committer | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2010-06-09 22:37:37 +0000 |
commit | 31811812f96429fd78f08ab106cf31f7390f1040 (patch) | |
tree | ab0611567018112b4e219bc304b40d394d2b0375 /Foundation | |
parent | 76632a4bbd4329310a5965b21047f10ee3aa171c (diff) |
[Author: dmaclach]
Add unsigned values to NSScanner.
R=thomasvl
DELTA=228 (228 added, 0 deleted, 0 changed)
Diffstat (limited to 'Foundation')
-rw-r--r-- | Foundation/GTMNSScanner+Unsigned.h | 30 | ||||
-rw-r--r-- | Foundation/GTMNSScanner+Unsigned.m | 60 | ||||
-rw-r--r-- | Foundation/GTMNSScanner+UnsignedTest.m | 116 |
3 files changed, 206 insertions, 0 deletions
diff --git a/Foundation/GTMNSScanner+Unsigned.h b/Foundation/GTMNSScanner+Unsigned.h new file mode 100644 index 0000000..307ac82 --- /dev/null +++ b/Foundation/GTMNSScanner+Unsigned.h @@ -0,0 +1,30 @@ +// +// GTMNSScanner+Unsigned.h +// +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import <Foundation/Foundation.h> + +// Adds support for working with unsigned values. Unsigned values are digits +// only [0-9]. There is no support for "+" or "-" signs. Overflow is handled +// by returning "YES" and the maximum value allowed for the type. +@interface NSScanner (GTMUnsignedAdditions) + +- (BOOL)gtm_scanUnsignedInt:(unsigned int *)value; +- (BOOL)gtm_scanUInteger:(NSUInteger *)value; +- (BOOL)gtm_scanUnsignedLongLong:(unsigned long long *)value; + +@end diff --git a/Foundation/GTMNSScanner+Unsigned.m b/Foundation/GTMNSScanner+Unsigned.m new file mode 100644 index 0000000..9228ba2 --- /dev/null +++ b/Foundation/GTMNSScanner+Unsigned.m @@ -0,0 +1,60 @@ +// +// GTMNSScanner+Unsigned.m +// +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMNSScanner+Unsigned.h" +#include <stdlib.h> +#include <limits.h> + +@implementation NSScanner (GTMUnsignedAdditions) + +- (BOOL)gtm_scanUnsignedInt:(unsigned int *)value { + unsigned long long uLongLongValue = 0; + BOOL wasGood = [self gtm_scanUnsignedLongLong:&uLongLongValue]; + if (wasGood && value) { + if (uLongLongValue > UINT_MAX) { + *value = UINT_MAX; + } else { + *value = (unsigned int)uLongLongValue; + } + } + return wasGood; +} + +- (BOOL)gtm_scanUInteger:(NSUInteger *)value { +#if defined(__LP64__) && __LP64__ + return [self gtm_scanUnsignedLongLong:(unsigned long long*)value]; +#else + return [self gtm_scanUnsignedInt:value]; +#endif // defined(__LP64__) && __LP64__ +} + +- (BOOL)gtm_scanUnsignedLongLong:(unsigned long long *)value { + // Slow path + NSCharacterSet *decimalSet = [NSCharacterSet decimalDigitCharacterSet]; + NSString *digitString = nil; + BOOL wasGood = [self scanCharactersFromSet:decimalSet intoString:&digitString]; + if (wasGood) { + const char *digitChars = [digitString UTF8String]; + if (value) { + *value = strtoull(digitChars, NULL, 10); + } + } + return wasGood; +} + +@end diff --git a/Foundation/GTMNSScanner+UnsignedTest.m b/Foundation/GTMNSScanner+UnsignedTest.m new file mode 100644 index 0000000..aab92f3 --- /dev/null +++ b/Foundation/GTMNSScanner+UnsignedTest.m @@ -0,0 +1,116 @@ +// +// GTMNSScanner+UnsignedTest.m +// +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMSenTestCase.h" +#import "GTMNSScanner+Unsigned.h" + +@interface GTMNSScanner_UnsignedTest : GTMTestCase +@end + +@implementation GTMNSScanner_UnsignedTest + +#define TEST_BLOCK(A_MAX_VALUE) \ + { @"-1", 0, NO, 0 }, \ + { @"- 1", 0, NO, 0 }, \ + { @" - 1", 0, NO, 0 }, \ + { @"+ 1", 1, NO, 0 }, \ + { @" + 1", 1, NO, 0 }, \ + { @"0", 0, YES, 1 }, \ + { @"a", 0, NO, 0 }, \ + { @" ", 0, NO, 0 }, \ + { @"-1a", 0, NO, 0 }, \ + { @"a1", 0, NO, 0 }, \ + { @"1 ", 1, YES, 1 }, \ + { @"2 1 ", 2, YES, 1 }, \ + { @" 2 1 ", 2, YES, 2 }, \ + { @"99999999999999999999999999999999999", A_MAX_VALUE, YES, 35 } + +- (void)testScanUnsignedInt { + struct { + NSString *string; + unsigned int val; + BOOL goodScan; + NSUInteger location; + } testStruct[] = { + TEST_BLOCK(UINT_MAX), + }; + for (size_t i = 0; i < sizeof(testStruct) / sizeof(testStruct[0]); ++i) { + NSScanner *scanner = [NSScanner scannerWithString:testStruct[i].string]; + STAssertNotNil(scanner, nil); + unsigned int value; + BOOL isGood = [scanner gtm_scanUnsignedInt:&value]; + STAssertEquals((int)isGood, (int)testStruct[i].goodScan, + @"%@", testStruct[i].string); + if (isGood && testStruct[i].goodScan) { + STAssertEquals(value, testStruct[i].val, @"%@", testStruct[i].string); + } + STAssertEquals(testStruct[i].location, [scanner scanLocation], + @"%@", testStruct[i].string); + } +} + +- (void)testScanUInteger { + struct { + NSString *string; + NSUInteger val; + BOOL goodScan; + NSUInteger location; + } testStruct[] = { + TEST_BLOCK(NSUIntegerMax), + }; + for (size_t i = 0; i < sizeof(testStruct) / sizeof(testStruct[0]); ++i) { + NSScanner *scanner = [NSScanner scannerWithString:testStruct[i].string]; + STAssertNotNil(scanner, nil); + NSUInteger value; + BOOL isGood = [scanner gtm_scanUInteger:&value]; + STAssertEquals((int)isGood, (int)testStruct[i].goodScan, + @"%@", testStruct[i].string); + if (isGood && testStruct[i].goodScan) { + STAssertEquals(value, testStruct[i].val, @"%@", testStruct[i].string); + } + STAssertEquals(testStruct[i].location, [scanner scanLocation], + @"%@", testStruct[i].string); + } +} + +- (void)testScanUnsignedLongLong { + struct { + NSString *string; + unsigned long long val; + BOOL goodScan; + NSUInteger location; + } testStruct[] = { + TEST_BLOCK(ULLONG_MAX), + { @"4294967296", ((unsigned long long)UINT_MAX) + 1, YES, 10 } + }; + for (size_t i = 0; i < sizeof(testStruct) / sizeof(testStruct[0]); ++i) { + NSScanner *scanner = [NSScanner scannerWithString:testStruct[i].string]; + STAssertNotNil(scanner, nil); + unsigned long long value; + BOOL isGood = [scanner gtm_scanUnsignedLongLong:&value]; + STAssertEquals((int)isGood, (int)testStruct[i].goodScan, + @"%@", testStruct[i].string); + if (isGood && testStruct[i].goodScan) { + STAssertEquals(value, testStruct[i].val, @"%@", testStruct[i].string); + } + STAssertEquals(testStruct[i].location, [scanner scanLocation], + @"%@", testStruct[i].string); + } +} + +@end |