FSTArraySortedDictionary.m 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #import "Firestore/third_party/Immutable/FSTArraySortedDictionary.h"
  2. #import "Firestore/third_party/Immutable/FSTArraySortedDictionaryEnumerator.h"
  3. #import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h"
  4. NS_ASSUME_NONNULL_BEGIN
  5. @interface FSTArraySortedDictionary ()
  6. @property(nonatomic, copy, readwrite) NSComparator comparator;
  7. @property(nonatomic, strong) NSArray<id> *keys;
  8. @property(nonatomic, strong) NSArray<id> *values;
  9. @end
  10. @implementation FSTArraySortedDictionary
  11. + (FSTArraySortedDictionary *)dictionaryWithDictionary:(NSDictionary *)dictionary
  12. comparator:(NSComparator)comparator {
  13. NSMutableArray *keys = [NSMutableArray arrayWithCapacity:dictionary.count];
  14. [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  15. [keys addObject:key];
  16. }];
  17. [keys sortUsingComparator:comparator];
  18. [keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  19. if (idx > 0) {
  20. if (comparator(keys[idx - 1], obj) != NSOrderedAscending) {
  21. [NSException raise:NSInvalidArgumentException
  22. format:
  23. @"Can't create FSTImmutableSortedDictionary with keys "
  24. @"with same ordering!"];
  25. }
  26. }
  27. }];
  28. NSMutableArray *values = [NSMutableArray arrayWithCapacity:keys.count];
  29. NSInteger pos = 0;
  30. for (id key in keys) {
  31. values[pos++] = dictionary[key];
  32. }
  33. NSAssert(values.count == keys.count, @"We added as many keys as values");
  34. return [[FSTArraySortedDictionary alloc] initWithComparator:comparator keys:keys values:values];
  35. }
  36. - (id)initWithComparator:(NSComparator)comparator {
  37. return [self initWithComparator:comparator keys:[NSArray array] values:[NSArray array]];
  38. }
  39. // Designated initializer.
  40. - (id)initWithComparator:(NSComparator)comparator keys:(NSArray *)keys values:(NSArray *)values {
  41. self = [super init];
  42. if (self != nil) {
  43. NSAssert(keys.count == values.count, @"keys and values must have the same count");
  44. _comparator = comparator;
  45. _keys = keys;
  46. _values = values;
  47. }
  48. return self;
  49. }
  50. /** Returns the index of the first position where array[position] >= key. */
  51. - (int)findInsertPositionForKey:(id)key {
  52. int newPos = 0;
  53. while (newPos < self.keys.count && self.comparator(self.keys[newPos], key) < NSOrderedSame) {
  54. newPos++;
  55. }
  56. return newPos;
  57. }
  58. - (NSInteger)findKey:(id)key {
  59. if (key == nil) {
  60. return NSNotFound;
  61. }
  62. for (NSInteger pos = 0; pos < self.keys.count; pos++) {
  63. NSComparisonResult result = self.comparator(key, self.keys[pos]);
  64. if (result == NSOrderedSame) {
  65. return pos;
  66. } else if (result == NSOrderedAscending) {
  67. return NSNotFound;
  68. }
  69. }
  70. return NSNotFound;
  71. }
  72. - (FSTImmutableSortedDictionary *)dictionaryBySettingObject:(id)value forKey:(id)key {
  73. NSInteger pos = [self findKey:key];
  74. if (pos == NSNotFound) {
  75. /*
  76. * If we're above the threshold we want to convert it to a tree backed implementation to not
  77. * have degrading performance
  78. */
  79. if (self.count >= kSortedDictionaryArrayToRBTreeSizeThreshold) {
  80. NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:self.count];
  81. for (NSInteger i = 0; i < self.keys.count; i++) {
  82. dict[self.keys[i]] = self.values[i];
  83. }
  84. dict[key] = value;
  85. return [FSTTreeSortedDictionary dictionaryWithDictionary:dict comparator:self.comparator];
  86. } else {
  87. NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys];
  88. NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values];
  89. NSInteger newPos = [self findInsertPositionForKey:key];
  90. [newKeys insertObject:key atIndex:newPos];
  91. [newValues insertObject:value atIndex:newPos];
  92. return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator
  93. keys:newKeys
  94. values:newValues];
  95. }
  96. } else {
  97. NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys];
  98. NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values];
  99. newKeys[pos] = key;
  100. newValues[pos] = value;
  101. return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator
  102. keys:newKeys
  103. values:newValues];
  104. }
  105. }
  106. - (FSTImmutableSortedDictionary *)dictionaryByRemovingObjectForKey:(id)key {
  107. NSInteger pos = [self findKey:key];
  108. if (pos == NSNotFound) {
  109. return self;
  110. } else {
  111. NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys];
  112. NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values];
  113. [newKeys removeObjectAtIndex:pos];
  114. [newValues removeObjectAtIndex:pos];
  115. return [[FSTArraySortedDictionary alloc] initWithComparator:self.comparator
  116. keys:newKeys
  117. values:newValues];
  118. }
  119. }
  120. - (nullable id)objectForKey:(id)key {
  121. NSInteger pos = [self findKey:key];
  122. if (pos == NSNotFound) {
  123. return nil;
  124. } else {
  125. return self.values[pos];
  126. }
  127. }
  128. - (NSUInteger)indexOfKey:(id)key {
  129. return [self findKey:key];
  130. }
  131. - (BOOL)isEmpty {
  132. return self.keys.count == 0;
  133. }
  134. - (NSUInteger)count {
  135. return self.keys.count;
  136. }
  137. - (id)minKey {
  138. return [self.keys firstObject];
  139. }
  140. - (id)maxKey {
  141. return [self.keys lastObject];
  142. }
  143. - (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block {
  144. [self enumerateKeysAndObjectsReverse:NO usingBlock:block];
  145. }
  146. - (void)enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block {
  147. if (reverse) {
  148. BOOL stop = NO;
  149. for (NSInteger i = self.keys.count - 1; i >= 0; i--) {
  150. block(self.keys[i], self.values[i], &stop);
  151. if (stop) return;
  152. }
  153. } else {
  154. BOOL stop = NO;
  155. for (NSInteger i = 0; i < self.keys.count; i++) {
  156. block(self.keys[i], self.values[i], &stop);
  157. if (stop) return;
  158. }
  159. }
  160. }
  161. - (BOOL)containsKey:(id)key {
  162. return [self findKey:key] != NSNotFound;
  163. }
  164. - (NSEnumerator *)keyEnumerator {
  165. return [self.keys objectEnumerator];
  166. }
  167. - (NSEnumerator *)keyEnumeratorFrom:(id)startKey {
  168. return [self keyEnumeratorFrom:startKey to:nil];
  169. }
  170. - (NSEnumerator *)keyEnumeratorFrom:(id)startKey to:(nullable id)endKey {
  171. int start = [self findInsertPositionForKey:startKey];
  172. int end = (int)self.count;
  173. if (endKey) {
  174. end = [self findInsertPositionForKey:endKey];
  175. }
  176. return [[FSTArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys
  177. startPos:start
  178. endPos:end
  179. isReverse:NO];
  180. }
  181. - (NSEnumerator *)reverseKeyEnumerator {
  182. return [self.keys reverseObjectEnumerator];
  183. }
  184. - (NSEnumerator *)reverseKeyEnumeratorFrom:(id)startKey {
  185. int startPos = [self findInsertPositionForKey:startKey];
  186. // if there's no exact match, findKeyOrInsertPosition will return the index *after* the closest
  187. // match, but since this is a reverse iterator, we want to start just *before* the closest match.
  188. if (startPos >= self.keys.count ||
  189. self.comparator(self.keys[startPos], startKey) != NSOrderedSame) {
  190. startPos -= 1;
  191. }
  192. return [[FSTArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys
  193. startPos:startPos
  194. endPos:-1
  195. isReverse:YES];
  196. }
  197. @end
  198. NS_ASSUME_NONNULL_END