/
ODLazyMutableArray.m
177 lines (145 loc) · 4.58 KB
/
ODLazyMutableArray.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
// Created by ilya on 10/21/13.
// Copyright (c) 2013 Ilya Nikokoshev. All rights reserved.
//
#import "ODLazyMutableArray.h"
@implementation ODLazyMutableArray {
NSMutableArray *_objects; // Created lazily, only on -setCount:, insert/add object.
}
- (id)init {
return [self initWithDelegate:nil];
}
- (id)initWithDelegate:(id<ODLazyMutableArrayDelegate>)delegate {
if (self = [super init]) {
_delegate = delegate;
}
return self;
}
- (id)initWithDelegate:(id<ODLazyMutableArrayDelegate>)delegate contents:(NSArray *)array {
if (self = [self initWithDelegate:delegate]) {
_count = [array count];
_objects = [array mutableCopy];
}
return self;
}
- (void)setCount:(NSUInteger)count {
if (self.size > count) {
self.size = count;
}
_count = count;
}
- (NSUInteger)size {
return _objects.count;
}
- (void)growTo:(NSUInteger)size {
if (!_objects && size) {
_objects = [NSMutableArray new];
}
id singleton = [self singleton];
while (_objects.count < size) {
[_objects addObject:singleton];
}
NSAssert(self.size >= size, @"We didn't grow contents correctly, it seems.");
}
- (void)setSize:(NSUInteger)size {
if (_objects.count < size) {
[self growTo:size];
}
if (_objects && !size) {
_objects = nil;
}
if (_objects.count > size) {
NSRange range = NSMakeRange(size, _objects.count - size);
[_objects removeObjectsInRange:range];
}
NSAssert(self.size == size, @"We didn't set the size correctly, it seems.");
}
- (id)objectAtIndex:(NSUInteger)index {
if (index >= self.count) {
return nil;
}
id singleton = [self singleton];
@autoreleasepool {
[self growTo:index + 1];
__weak id object = _objects[index];
if (object != singleton) {
return object;
}
}
NSArray *missing = [self.delegate array:self missingObjectsFromIndex:index];
if (!missing.count) {
@throw([NSException exceptionWithName:NSObjectNotAvailableException
reason:@"Delegate was not able to provide a non-nil element to a lazy array"
userInfo:nil]);
}
[missing enumerateObjectsUsingBlock:^(id obj, NSUInteger jdx, BOOL *stop) {
if (index + jdx >= _objects.count || _objects[index + jdx] == singleton) {
_objects[index + jdx] = obj;
}
}];
return _objects[index];
}
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
if (index >= self.count) {
return;
}
[self growTo:index];
if (!anObject) {
anObject = [self singleton];
}
if (index == _objects.count) {
[_objects addObject:anObject];
} else {
[_objects replaceObjectAtIndex:index withObject:anObject];
}
}
//- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index {
// [self replaceObjectAtIndex:(NSUInteger)index withObject:(id)object];
//}
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
if (index != self.count) {
@throw([NSException exceptionWithName:NSRangeException
reason:@"This class does not support inserting element except at the end"
userInfo:nil]);
}
[self addObject:anObject];
}
- (void)addObject:(id)anObject {
self.size = _count;
if (!_objects) {
_objects = [NSMutableArray new];
}
[_objects addObject:anObject];
_count++;
NSAssert(self.count == self.size, @"After adding an object, array should be completely full");
}
- (void)removeLastObject {
self.count--;
}
- (void)removeObjectAtIndex:(NSUInteger)index {
if (index != self.count) {
@throw([NSException exceptionWithName:NSRangeException
reason:@"This class does not support removing element except at the end"
userInfo:nil]);
}
[self removeLastObject];
}
- (id)singleton {
static id singleton;
if (!singleton) {
singleton = [NSValue valueWithPointer:&singleton];
}
return singleton;
}
- (void)cleanWeakElements {
id singleton = [self singleton];
for (NSUInteger index = 0; index < _objects.count; index ++) {
__weak id obj = _objects[index];
if (obj != singleton) {
// If this was the only strong reference, obj is deallocated here.
_objects[index] = singleton;
if (obj) _objects[index] = obj;
}
}
}
@end