• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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