FSTArraySortedDictionary.m 8.0 KB

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