| import Swift |
| import StdlibUnittest |
| #if _runtime(_ObjC) |
| import Darwin |
| import Foundation |
| #endif |
| |
| |
| #if _runtime(_ObjC) |
| |
| /// Expect some number of autoreleased value objects. |
| /// |
| /// - parameter opt: applies to platforms that have the return-autoreleased |
| /// optimization. |
| /// |
| /// - parameter unopt: applies to platforms that don't. |
| /// |
| /// FIXME: Some non-zero `opt` might be cases of missed return-autorelease. |
| func expectAutoreleasedValues( |
| opt: Int = 0, unopt: Int = 0) { |
| _expectAutoreleasedKeysAndValues(opt: (0, opt), unopt: (0, unopt)) |
| } |
| |
| func isNativeNSArray(_ d: NSArray) -> Bool { |
| let className: NSString = NSStringFromClass(type(of: d)) as NSString |
| return ["_SwiftDeferredNSArray", "_ContiguousArray", "_EmptyArray"].contains { |
| className.range(of: $0).length > 0 |
| } |
| } |
| |
| func isCocoaNSArray(_ a: NSArray) -> Bool { |
| let className: NSString = NSStringFromClass(type(of: a)) as NSString |
| return className.range(of: "NSArray").length > 0 || |
| className.range(of: "NSCFArray").length > 0 |
| } |
| |
| func getBridgedNSArrayOfRefTypesBridgedVerbatim() -> NSArray { |
| expectTrue(_isBridgedVerbatimToObjectiveC(TestObjCValueTy.self)) |
| |
| var a = Array<TestObjCValueTy>() |
| a.reserveCapacity(32) |
| a.append(TestObjCValueTy(1010)) |
| a.append(TestObjCValueTy(1020)) |
| a.append(TestObjCValueTy(1030)) |
| |
| let bridged = convertArrayToNSArray(a) |
| |
| assert(isNativeNSArray(bridged)) |
| |
| return bridged |
| } |
| |
| func getBridgedEmptyNSArray() -> NSArray { |
| let a = Array<TestObjCValueTy>() |
| |
| let bridged = convertArrayToNSArray(a) |
| assert(isNativeNSArray(bridged)) |
| |
| return bridged |
| } |
| |
| #endif |
| |
| func getDerivedAPIsArray() -> Array<Int> { |
| var a = Array<Int>() |
| a.append(1010) |
| a.append(1020) |
| a.append(1030) |
| return a |
| } |
| |
| func _makeExpectedArrayContents( |
| _ expected: [Int] |
| ) -> [ExpectedArrayElement] { |
| var result = [ExpectedArrayElement]() |
| for value in expected { |
| result.append(ExpectedArrayElement(value: value)) |
| } |
| return result |
| } |
| |
| func _equalsWithoutElementIdentity( |
| _ lhs: [ExpectedArrayElement], _ rhs: [ExpectedArrayElement] |
| ) -> Bool { |
| func stripIdentity( |
| _ list: [ExpectedArrayElement] |
| ) -> [ExpectedArrayElement] { |
| return list.map { ExpectedArrayElement(value: $0.value) } |
| } |
| |
| return stripIdentity(lhs).elementsEqual(stripIdentity(rhs)) |
| } |
| |
| struct ExpectedArrayElement : Comparable, CustomStringConvertible { |
| var value: Int |
| var valueIdentity: UInt |
| |
| init(value: Int, valueIdentity: UInt = 0) { |
| self.value = value |
| self.valueIdentity = valueIdentity |
| } |
| |
| var description: String { |
| return "(\(value), \(valueIdentity))" |
| } |
| } |
| |
| func == ( |
| lhs: ExpectedArrayElement, |
| rhs: ExpectedArrayElement |
| ) -> Bool { |
| return |
| lhs.value == rhs.value && |
| lhs.valueIdentity == rhs.valueIdentity |
| } |
| |
| func < ( |
| lhs: ExpectedArrayElement, |
| rhs: ExpectedArrayElement |
| ) -> Bool { |
| let lhsElements = [ lhs.value, Int(bitPattern: lhs.valueIdentity) ] |
| let rhsElements = [ rhs.value, Int(bitPattern: rhs.valueIdentity) ] |
| return lhsElements.lexicographicallyPrecedes(rhsElements) |
| } |
| |
| #if _runtime(_ObjC) |
| func _checkArrayFastEnumerationImpl( |
| _ expected: [Int], |
| _ a: NSArray, |
| _ makeEnumerator: () -> NSFastEnumeration, |
| _ useEnumerator: (NSArray, NSFastEnumeration, (AnyObject) -> ()) -> Void, |
| _ convertValue: @escaping (AnyObject) -> Int |
| ) { |
| let expectedContentsWithoutIdentity = |
| _makeExpectedArrayContents(expected) |
| |
| var expectedContents = [ExpectedArrayElement]() |
| |
| for i in 0..<3 { |
| var actualContents = [ExpectedArrayElement]() |
| let sink = { |
| (value: AnyObject) in |
| actualContents.append(ExpectedArrayElement( |
| value: convertValue(value), |
| valueIdentity: unsafeBitCast(value, to: UInt.self))) |
| } |
| |
| useEnumerator(a, makeEnumerator(), sink) |
| |
| expectTrue( |
| _equalsWithoutElementIdentity( |
| expectedContentsWithoutIdentity, actualContents), |
| "expected: \(expectedContentsWithoutIdentity)\n" + |
| "actual: \(actualContents)\n") |
| |
| if i == 0 { |
| expectedContents = actualContents |
| } |
| |
| expectEqualSequence(expectedContents, actualContents) |
| } |
| } |
| #endif |
| |
| func getCOWFastArray() -> Array<Int> { |
| var a = Array<Int>() |
| a.reserveCapacity(10) |
| a.append(1) |
| a.append(2) |
| a.append(3) |
| return a |
| } |
| |
| func getCOWSlowArray() -> Array<COWBox<Int>> { |
| var a = Array<COWBox<Int>>() |
| a.reserveCapacity(10) |
| a.append(COWBox(1)) |
| a.append(COWBox(2)) |
| a.append(COWBox(3)) |
| return a |
| } |
| |
| #if _runtime(_ObjC) |
| func slurpFastEnumerationFromObjC( |
| _ a: NSArray, _ fe: NSFastEnumeration, _ sink: (AnyObject) -> Void |
| ) { |
| let objcValues = NSMutableArray() |
| slurpFastEnumerationOfArrayFromObjCImpl(a, fe, objcValues) |
| for value in objcValues { |
| sink(value as AnyObject) |
| } |
| } |
| |
| import SlurpFastEnumeration |
| |
| func slurpFastEnumerationFromSwift( |
| _ a: NSArray, _ fe: NSFastEnumeration, _ sink: (AnyObject) -> Void, |
| maxItems: Int? = nil |
| ) { |
| var state = NSFastEnumerationState() |
| |
| let stackBufLength = 3 |
| let stackBuf = _HeapBuffer<(), AnyObject?>( |
| _HeapBufferStorage<(), AnyObject?>.self, (), stackBufLength) |
| |
| var itemsReturned = 0 |
| while true { |
| let returnedCount = fe.countByEnumerating( |
| with: &state, objects: AutoreleasingUnsafeMutablePointer(stackBuf.baseAddress), |
| count: stackBufLength) |
| expectNotEqual(0, state.state) |
| expectNotNil(state.mutationsPtr) |
| if returnedCount == 0 { |
| break |
| } |
| for i in 0..<returnedCount { |
| let value: AnyObject = state.itemsPtr![i]! |
| sink(value) |
| itemsReturned += 1 |
| } |
| if maxItems != nil && itemsReturned >= maxItems! { |
| return |
| } |
| } |
| |
| for _ in 0..<3 { |
| let returnedCount = fe.countByEnumerating( |
| with: &state, objects: AutoreleasingUnsafeMutablePointer(stackBuf.baseAddress), |
| count: stackBufLength) |
| expectNotEqual(0, state.state) |
| expectNotNil(state.mutationsPtr) |
| expectEqual(0, returnedCount) |
| } |
| } |
| |
| func checkArrayFastEnumerationFromSwift( |
| _ expected: [Int], |
| _ a: NSArray, _ makeEnumerator: () -> NSFastEnumeration, |
| _ convertValue: @escaping (AnyObject) -> Int |
| ) { |
| _checkArrayFastEnumerationImpl( |
| expected, a, makeEnumerator, |
| { (a, fe, sink) in |
| slurpFastEnumerationFromSwift(a, fe, sink) |
| }, |
| convertValue) |
| } |
| |
| func checkArrayFastEnumerationFromObjC( |
| _ expected: [Int], |
| _ a: NSArray, _ makeEnumerator: () -> NSFastEnumeration, |
| _ convertValue: @escaping (AnyObject) -> Int |
| ) { |
| _checkArrayFastEnumerationImpl( |
| expected, a, makeEnumerator, |
| { (a, fe, sink) in |
| slurpFastEnumerationFromObjC(a, fe, sink) |
| }, |
| convertValue) |
| } |
| |
| func getBridgedNSArrayOfObjValue_ValueTypesCustomBridged( |
| numElements: Int = 3 |
| ) -> NSArray { |
| expectFalse(_isBridgedVerbatimToObjectiveC(TestBridgedValueTy.self)) |
| |
| var a = Array<TestBridgedValueTy>() |
| for i in 1..<(numElements + 1) { |
| a.append(TestBridgedValueTy(i * 10 + 1000)) |
| } |
| |
| let bridged = convertArrayToNSArray(a) |
| expectTrue(isNativeNSArray(bridged)) |
| |
| return bridged |
| } |
| |
| func checkArrayEnumeratorPartialFastEnumerationFromSwift( |
| _ expected: [Int], |
| _ a: NSArray, |
| maxFastEnumerationItems: Int, |
| _ convertValue: @escaping (AnyObject) -> Int |
| ) { |
| _checkArrayFastEnumerationImpl( |
| expected, a, { a.objectEnumerator() }, |
| { (a, fe, sink) in |
| slurpFastEnumerationOfNSEnumeratorFromSwift( |
| a, fe as! NSEnumerator, sink, |
| maxFastEnumerationItems: maxFastEnumerationItems) |
| }, |
| convertValue) |
| } |
| |
| func slurpFastEnumerationOfNSEnumeratorFromSwift( |
| _ a: NSArray, _ enumerator: NSEnumerator, _ sink: (AnyObject) -> Void, |
| maxFastEnumerationItems: Int |
| ) { |
| slurpFastEnumerationFromSwift( |
| a, enumerator, sink, maxItems: maxFastEnumerationItems) |
| while let value = enumerator.nextObject() { |
| sink(value as AnyObject) |
| } |
| } |
| |
| func _expectAutoreleasedKeysAndValues( |
| opt: (Int, Int) = (0, 0), unopt: (Int, Int) = (0, 0)) { |
| var expectedKeys = 0 |
| var expectedValues = 0 |
| #if arch(i386) |
| (expectedKeys, expectedValues) = unopt |
| #else |
| (expectedKeys, expectedValues) = opt |
| #endif |
| |
| TestObjCValueTy.objectCount -= expectedValues |
| } |
| |
| func isCocoaArray<T>(_ a: Array<T>) -> Bool { |
| return !isNativeArray(a) |
| } |
| |
| func isNativeArray<T>(_ a: Array<T>) -> Bool { |
| return a._buffer._storage.isNative |
| } |
| |
| func convertArrayToNSArray<T>(_ a: [T]) -> NSArray { |
| return a._bridgeToObjectiveC() |
| } |
| |
| func convertNSArrayToArray<T>(_ a: NSArray?) -> [T] { |
| if _slowPath(a == nil) { return [] } |
| var result: [T]? |
| Array._forceBridgeFromObjectiveC(a!, result: &result) |
| return result! |
| } |
| |
| func getAsNSArray(_ a: Array<Int>) -> NSArray { |
| let values = Array(a.map { TestObjCValueTy($0) }) |
| |
| // Return an `NSMutableArray` to make sure that it has a unique |
| // pointer identity. |
| let nsarray = NSMutableArray() |
| nsarray.addObjects(from: values) |
| return nsarray |
| } |
| |
| func getAsEquatableNSArray(_ a: Array<Int>) -> NSArray { |
| let values = Array(a.map { TestObjCEquatableValueTy($0) }) |
| |
| // Return an `NSMutableArray` to make sure that it has a unique |
| // pointer identity. |
| let nsarray = NSMutableArray() |
| nsarray.addObjects(from: values) |
| return nsarray |
| } |
| |
| func getAsNSMutableArray(_ a: Array<Int>) -> NSMutableArray { |
| let values = Array(a.map { TestObjCValueTy($0) }) |
| let nsarray = NSMutableArray() |
| nsarray.addObjects(from: values) |
| return nsarray |
| } |
| |
| func getBridgedVerbatimArrayAndNSMutableArray() |
| -> (Array<AnyObject>, NSMutableArray) { |
| let nsa = getAsNSMutableArray([1010, 1020, 1030]) |
| return (convertNSArrayToArray(nsa), nsa) |
| } |
| |
| func getBridgedVerbatimArray() -> Array<AnyObject> { |
| let nsa = getAsNSArray([1010, 1020, 1030]) |
| return convertNSArrayToArray(nsa) |
| } |
| |
| func getBridgedVerbatimArray(_ a: Array<Int>) -> Array<AnyObject> { |
| let nsa = getAsNSArray(a) |
| return convertNSArrayToArray(nsa) |
| } |
| |
| func getBridgedNonverbatimArray() -> Array<TestBridgedValueTy> { |
| let nsa = getAsNSArray([1010, 1020, 1030 ]) |
| return Swift._forceBridgeFromObjectiveC(nsa, Array.self) |
| } |
| |
| func getBridgedNonverbatimArray(_ a: Array<Int>) -> Array<TestBridgedValueTy> { |
| let nsa = getAsNSArray(a) |
| return Swift._forceBridgeFromObjectiveC(nsa, Array.self) |
| } |
| |
| func getBridgedNonverbatimArrayAndNSMutableArray() |
| -> (Array<TestBridgedValueTy>, NSMutableArray) { |
| let nsa = getAsNSMutableArray([1010, 1020, 1030]) |
| return (Swift._forceBridgeFromObjectiveC(nsa, Array.self), nsa) |
| } |
| |
| func getBridgedVerbatimEquatableArray(_ a: Array<Int>) |
| -> Array<TestObjCEquatableValueTy> { |
| let nsa = getAsEquatableNSArray(a) |
| return convertNSArrayToArray(nsa) |
| } |
| |
| func getBridgedNonverbatimEquatableArray(_ a: Array<Int>) |
| -> Array<TestBridgedEquatableValueTy> { |
| let nsa = getAsEquatableNSArray(a) |
| return Swift._forceBridgeFromObjectiveC(nsa, Array.self) |
| } |
| |
| func getHugeBridgedVerbatimArrayHelper() -> NSArray { |
| let values = (1...32).map { TestObjCValueTy(1000 + $0) } |
| |
| let nsa = NSMutableArray() |
| nsa.addObjects(from: values) |
| return nsa |
| } |
| |
| func getHugeBridgedVerbatimArray() -> Array<AnyObject> { |
| let nsa = getHugeBridgedVerbatimArrayHelper() |
| return convertNSArrayToArray(nsa) |
| } |
| |
| func getHugeBridgedNonverbatimArray() |
| -> Array<TestBridgedValueTy> { |
| let nsa = getHugeBridgedVerbatimArrayHelper() |
| return Swift._forceBridgeFromObjectiveC(nsa, Array.self) |
| } |
| |
| func getBridgedNSArrayOfObj_ValueTypeCustomBridged() -> NSArray { |
| expectTrue(_isBridgedVerbatimToObjectiveC(TestObjCValueTy.self)) |
| |
| var a = Array<TestObjCValueTy>() |
| a.append(TestObjCValueTy(1010)) |
| a.append(TestObjCValueTy(1020)) |
| a.append(TestObjCValueTy(1030)) |
| |
| let bridged = convertArrayToNSArray(a) |
| expectTrue(isNativeNSArray(bridged)) |
| |
| return bridged |
| } |
| |
| func getBridgedNSArrayOfValue_ValueTypeCustomBridged() -> NSArray { |
| expectFalse(_isBridgedVerbatimToObjectiveC(TestBridgedValueTy.self)) |
| |
| var a = Array<TestBridgedValueTy>() |
| a.append(TestBridgedValueTy(1010)) |
| a.append(TestBridgedValueTy(1020)) |
| a.append(TestBridgedValueTy(1030)) |
| |
| let bridged = convertArrayToNSArray(a) |
| expectTrue(isNativeNSArray(bridged)) |
| |
| return bridged |
| } |
| |
| func getRoundtripBridgedNSArray() -> NSArray { |
| let values = [ 1010, 1020, 1030 ].map { TestObjCValueTy($0) } |
| |
| let nsa = NSArray(array: values) |
| |
| let a: Array<AnyObject> = convertNSArrayToArray(nsa) |
| |
| let bridgedBack = convertArrayToNSArray(a) |
| expectTrue(isCocoaNSArray(bridgedBack)) |
| expectEqual(unsafeBitCast(nsa, to: Int.self), unsafeBitCast(bridgedBack, to: Int.self)) |
| |
| return bridgedBack |
| } |
| |
| var _objcValueCount = _stdlib_AtomicInt(0) |
| var _objcValueSerial = _stdlib_AtomicInt(0) |
| |
| class TestObjCValueTy : NSObject { |
| class var objectCount: Int { |
| get { |
| return _objcValueCount.load() |
| } |
| set { |
| _objcValueCount.store(newValue) |
| } |
| } |
| |
| init(_ value: Int) { |
| _objcValueCount.fetchAndAdd(1) |
| serial = _objcValueSerial.addAndFetch(1) |
| self.value = value |
| } |
| |
| deinit { |
| assert(serial > 0, "double destruction") |
| _objcValueCount.fetchAndAdd(-1) |
| serial = -serial |
| } |
| |
| override var description: String { |
| assert(serial > 0, "dead TestObjCValueTy") |
| return value.description |
| } |
| |
| var value: Int |
| var serial: Int |
| } |
| |
| var _objcEquatableValueCount = _stdlib_AtomicInt(0) |
| var _objcEquatableValueSerial = _stdlib_AtomicInt(0) |
| |
| class TestObjCEquatableValueTy : NSObject { |
| class var objectCount: Int { |
| get { |
| return _objcEquatableValueCount.load() |
| } |
| set { |
| _objcEquatableValueCount.store(newValue) |
| } |
| } |
| |
| init(_ value: Int) { |
| _objcEquatableValueCount.fetchAndAdd(1) |
| serial = _objcEquatableValueSerial.addAndFetch(1) |
| self.value = value |
| } |
| |
| deinit { |
| assert(serial > 0, "double destruction") |
| _objcEquatableValueCount.fetchAndAdd(-1) |
| serial = -serial |
| } |
| |
| override func isEqual(_ object: Any!) -> Bool { |
| if let other = object { |
| if let otherObjcKey = other as? TestObjCEquatableValueTy { |
| return self.value == otherObjcKey.value |
| } |
| } |
| return false |
| } |
| |
| override var description: String { |
| assert(serial > 0, "dead TestObjCValueTy") |
| return value.description |
| } |
| |
| var value: Int |
| var serial: Int |
| } |
| |
| func == (lhs: TestObjCEquatableValueTy, rhs: TestObjCEquatableValueTy) -> Bool { |
| return lhs.value == rhs.value |
| } |
| |
| var _bridgedValueSerial = _stdlib_AtomicInt(0) |
| var _bridgedValueBridgeOperations = _stdlib_AtomicInt(0) |
| |
| struct TestBridgedValueTy : CustomStringConvertible, _ObjectiveCBridgeable { |
| static var bridgeOperations: Int { |
| get { |
| return _bridgedValueBridgeOperations.load() |
| } |
| set { |
| _bridgedValueBridgeOperations.store(newValue) |
| } |
| } |
| |
| init(_ value: Int) { |
| serial = _bridgedValueSerial.fetchAndAdd(1) |
| self.value = value |
| } |
| |
| var description: String { |
| assert(serial > 0, "dead TestBridgedValueTy") |
| return value.description |
| } |
| |
| func _bridgeToObjectiveC() -> TestObjCValueTy { |
| TestBridgedValueTy.bridgeOperations += 1 |
| return TestObjCValueTy(value) |
| } |
| |
| static func _forceBridgeFromObjectiveC( |
| _ x: TestObjCValueTy, |
| result: inout TestBridgedValueTy? |
| ) { |
| TestBridgedValueTy.bridgeOperations += 1 |
| result = TestBridgedValueTy(x.value) |
| } |
| |
| static func _conditionallyBridgeFromObjectiveC( |
| _ x: TestObjCValueTy, |
| result: inout TestBridgedValueTy? |
| ) -> Bool { |
| self._forceBridgeFromObjectiveC(x, result: &result) |
| return true |
| } |
| |
| static func _unconditionallyBridgeFromObjectiveC(_ source: TestObjCValueTy?) |
| -> TestBridgedValueTy { |
| var result: TestBridgedValueTy? = nil |
| _forceBridgeFromObjectiveC(source!, result: &result) |
| return result! |
| } |
| |
| var value: Int |
| var serial: Int |
| } |
| |
| var _bridgedEquatableValueSerial = _stdlib_AtomicInt(0) |
| var _bridgedEquatableValueBridgeOperations = _stdlib_AtomicInt(0) |
| |
| struct TestBridgedEquatableValueTy |
| : Equatable, CustomStringConvertible, _ObjectiveCBridgeable { |
| |
| static var bridgeOperations: Int { |
| get { |
| return _bridgedEquatableValueBridgeOperations.load() |
| } |
| set { |
| _bridgedEquatableValueBridgeOperations.store(newValue) |
| } |
| } |
| |
| init(_ value: Int) { |
| serial = _bridgedEquatableValueSerial.addAndFetch(1) |
| self.value = value |
| } |
| |
| var description: String { |
| assert(serial > 0, "dead TestBridgedValueTy") |
| return value.description |
| } |
| |
| func _bridgeToObjectiveC() -> TestObjCEquatableValueTy { |
| _bridgedEquatableValueBridgeOperations.fetchAndAdd(1) |
| return TestObjCEquatableValueTy(value) |
| } |
| |
| static func _forceBridgeFromObjectiveC( |
| _ x: TestObjCEquatableValueTy, |
| result: inout TestBridgedEquatableValueTy? |
| ) { |
| _bridgedEquatableValueBridgeOperations.fetchAndAdd(1) |
| result = TestBridgedEquatableValueTy(x.value) |
| } |
| |
| static func _conditionallyBridgeFromObjectiveC( |
| _ x: TestObjCEquatableValueTy, |
| result: inout TestBridgedEquatableValueTy? |
| ) -> Bool { |
| self._forceBridgeFromObjectiveC(x, result: &result) |
| return true |
| } |
| |
| static func _unconditionallyBridgeFromObjectiveC( |
| _ source: TestObjCEquatableValueTy? |
| ) -> TestBridgedEquatableValueTy { |
| var result: TestBridgedEquatableValueTy? = nil |
| _forceBridgeFromObjectiveC(source!, result: &result) |
| return result! |
| } |
| |
| var value: Int |
| var serial: Int |
| } |
| |
| func == (lhs: TestBridgedEquatableValueTy, rhs: TestBridgedEquatableValueTy) -> Bool { |
| return lhs.value == rhs.value |
| } |
| |
| @objc |
| class CustomImmutableNSArray : NSArray { |
| init(_privateInit: ()) { |
| super.init() |
| } |
| |
| override init() { |
| expectUnreachable() |
| super.init() |
| } |
| |
| override init(objects: UnsafePointer<AnyObject>!, count cnt: Int) { |
| expectUnreachable() |
| super.init(objects: objects, count: cnt) |
| } |
| |
| required init?(coder aDecoder: NSCoder) { |
| fatalError("init(coder:) not implemented by CustomImmutableNSArray") |
| } |
| |
| @objc(copyWithZone:) |
| override func copy(with zone: NSZone?) -> Any { |
| CustomImmutableNSArray.timesCopyWithZoneWasCalled += 1 |
| return self |
| } |
| |
| override func object(at index: Int) -> Any { |
| CustomImmutableNSArray.timesObjectAtIndexWasCalled += 1 |
| return getAsNSArray([1010, 1020, 1030]).object(at: index) |
| } |
| |
| override func objectEnumerator() -> NSEnumerator { |
| CustomImmutableNSArray.timesObjectEnumeratorWasCalled += 1 |
| return getAsNSArray([1010, 1020, 1030]).objectEnumerator() |
| } |
| |
| override var count: Int { |
| CustomImmutableNSArray.timesCountWasCalled += 1 |
| return 3 |
| } |
| |
| static var timesCopyWithZoneWasCalled = 0 |
| static var timesObjectAtIndexWasCalled = 0 |
| static var timesObjectEnumeratorWasCalled = 0 |
| static var timesCountWasCalled = 0 |
| } |
| |
| #endif |