1/* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import "GRXNSFastEnumerator.h" 20 21@implementation GRXNSFastEnumerator { 22 id<NSFastEnumeration> _container; 23 NSFastEnumerationState _state; 24 // Number of elements of the container currently in the _state.itemsPtr array. 25 NSUInteger _count; 26 // The index of the next object to return from the _state.itemsPtr array. 27 NSUInteger _index; 28 // A "buffer of one element," for the containers that enumerate their elements one by one. Those 29 // will set _state.itemsPtr to point to this. 30 // The NSFastEnumeration protocol requires it to be __unsafe_unretained, but that's alright 31 // because the only use we'd make of its value is to return it immediately as the result of 32 // nextObject. 33 __unsafe_unretained id _bufferValue; 34 // Neither NSEnumerator nor NSFastEnumeration instances are required to work correctly when the 35 // underlying container is mutated during iteration. The expectation is that an exception is 36 // thrown when that happens. So we check for mutations. 37 unsigned long _mutationFlag; 38 BOOL _mutationFlagIsSet; 39} 40 41- (instancetype)init { 42 return [self initWithContainer:nil]; 43} 44 45// Designated initializer. 46- (instancetype)initWithContainer:(id<NSFastEnumeration>)container { 47 if ((self = [super init])) { 48 _container = container; 49 } 50 return self; 51} 52 53- (id)nextObject { 54 if (_index == _count) { 55 _index = 0; 56 _count = [_container countByEnumeratingWithState:&_state objects:&_bufferValue count:1]; 57 if (_count == 0) { 58 // Enumeration is over. 59 _container = nil; 60 return nil; 61 } 62 if (_mutationFlagIsSet) { 63 NSAssert(_mutationFlag == *(_state.mutationsPtr), 64 @"container was mutated while being enumerated"); 65 } else { 66 _mutationFlag = *(_state.mutationsPtr); 67 _mutationFlagIsSet = YES; 68 } 69 } 70 return _state.itemsPtr[_index++]; 71} 72@end 73