aboutsummaryrefslogtreecommitdiff
path: root/Foundation
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2010-06-09 22:37:37 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2010-06-09 22:37:37 +0000
commit31811812f96429fd78f08ab106cf31f7390f1040 (patch)
treeab0611567018112b4e219bc304b40d394d2b0375 /Foundation
parent76632a4bbd4329310a5965b21047f10ee3aa171c (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.h30
-rw-r--r--Foundation/GTMNSScanner+Unsigned.m60
-rw-r--r--Foundation/GTMNSScanner+UnsignedTest.m116
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