FSTTreeSortedDictionary.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #import "Firestore/third_party/Immutable/FSTTreeSortedDictionary.h"
  2. #import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h"
  3. #import "Firestore/third_party/Immutable/FSTLLRBValueNode.h"
  4. #import "Firestore/third_party/Immutable/FSTTreeSortedDictionaryEnumerator.h"
  5. NS_ASSUME_NONNULL_BEGIN
  6. @interface FSTTreeSortedDictionary ()
  7. - (FSTTreeSortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey;
  8. @property(nonatomic, strong) id<FSTLLRBNode> root;
  9. @property(nonatomic, copy, readwrite) NSComparator comparator;
  10. @end
  11. @implementation FSTTreeSortedDictionary
  12. + (FSTTreeSortedDictionary *)dictionaryWithDictionary:(NSDictionary *)dictionary
  13. comparator:(NSComparator)comparator {
  14. __block FSTTreeSortedDictionary *dict =
  15. [[FSTTreeSortedDictionary alloc] initWithComparator:comparator];
  16. [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  17. dict = [dict dictionaryBySettingObject:obj forKey:key];
  18. }];
  19. return dict;
  20. }
  21. - (id)initWithComparator:(NSComparator)aComparator {
  22. return [self initWithComparator:aComparator withRoot:[FSTLLRBEmptyNode emptyNode]];
  23. }
  24. // Designated initializer.
  25. - (id)initWithComparator:(NSComparator)aComparator withRoot:(id<FSTLLRBNode>)aRoot {
  26. self = [super init];
  27. if (self) {
  28. self.root = aRoot;
  29. self.comparator = aComparator;
  30. }
  31. return self;
  32. }
  33. /**
  34. * Returns a copy of the map, with the specified key/value added or replaced.
  35. */
  36. - (FSTTreeSortedDictionary *)dictionaryBySettingObject:(id)aValue forKey:(id)aKey {
  37. return [[FSTTreeSortedDictionary alloc]
  38. initWithComparator:self.comparator
  39. withRoot:[[self.root insertKey:aKey forValue:aValue withComparator:self.comparator]
  40. copyWith:nil
  41. withValue:nil
  42. withColor:FSTLLRBColorBlack
  43. withLeft:nil
  44. withRight:nil]];
  45. }
  46. - (FSTTreeSortedDictionary *)dictionaryByRemovingObjectForKey:(id)aKey {
  47. // Remove is somewhat expensive even if the key doesn't exist (the tree does rebalancing and
  48. // stuff). So avoid it.
  49. if (![self containsKey:aKey]) {
  50. return self;
  51. } else {
  52. return [[FSTTreeSortedDictionary alloc]
  53. initWithComparator:self.comparator
  54. withRoot:[[self.root remove:aKey withComparator:self.comparator]
  55. copyWith:nil
  56. withValue:nil
  57. withColor:FSTLLRBColorBlack
  58. withLeft:nil
  59. withRight:nil]];
  60. }
  61. }
  62. - (nullable id)objectForKey:(id)key {
  63. NSComparisonResult cmp;
  64. id<FSTLLRBNode> node = self.root;
  65. while (![node isEmpty]) {
  66. cmp = self.comparator(key, node.key);
  67. if (cmp == NSOrderedSame) {
  68. return node.value;
  69. } else if (cmp == NSOrderedAscending) {
  70. node = node.left;
  71. } else {
  72. node = node.right;
  73. }
  74. }
  75. return nil;
  76. }
  77. - (nullable id)predecessorKey:(id)key {
  78. NSComparisonResult cmp;
  79. id<FSTLLRBNode> node = self.root;
  80. id<FSTLLRBNode> rightParent = nil;
  81. while (![node isEmpty]) {
  82. cmp = self.comparator(key, node.key);
  83. if (cmp == NSOrderedSame) {
  84. if (![node.left isEmpty]) {
  85. node = node.left;
  86. while (![node.right isEmpty]) {
  87. node = node.right;
  88. }
  89. return node.key;
  90. } else if (rightParent != nil) {
  91. return rightParent.key;
  92. } else {
  93. return nil;
  94. }
  95. } else if (cmp == NSOrderedAscending) {
  96. node = node.left;
  97. } else if (cmp == NSOrderedDescending) {
  98. rightParent = node;
  99. node = node.right;
  100. }
  101. }
  102. @throw [NSException exceptionWithName:@"NonexistentKey"
  103. reason:@"getPredecessorKey called with nonexistent key."
  104. userInfo:@{@"key" : [key description]}];
  105. }
  106. - (NSUInteger)indexOfKey:(id)key {
  107. NSUInteger prunedNodes = 0;
  108. id<FSTLLRBNode> node = self.root;
  109. while (![node isEmpty]) {
  110. NSComparisonResult cmp = self.comparator(key, node.key);
  111. if (cmp == NSOrderedSame) {
  112. return prunedNodes + node.left.count;
  113. } else if (cmp == NSOrderedAscending) {
  114. node = node.left;
  115. } else if (cmp == NSOrderedDescending) {
  116. prunedNodes += node.left.count + 1;
  117. node = node.right;
  118. }
  119. }
  120. return NSNotFound;
  121. }
  122. - (BOOL)isEmpty {
  123. return [self.root isEmpty];
  124. }
  125. - (NSUInteger)count {
  126. return [self.root count];
  127. }
  128. - (id)minKey {
  129. return [self.root minKey];
  130. }
  131. - (id)maxKey {
  132. return [self.root maxKey];
  133. }
  134. - (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block {
  135. [self enumerateKeysAndObjectsReverse:NO usingBlock:block];
  136. }
  137. - (void)enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block {
  138. if (reverse) {
  139. __block BOOL stop = NO;
  140. [self.root reverseTraversal:^BOOL(id key, id value) {
  141. block(key, value, &stop);
  142. return stop;
  143. }];
  144. } else {
  145. __block BOOL stop = NO;
  146. [self.root inorderTraversal:^BOOL(id key, id value) {
  147. block(key, value, &stop);
  148. return stop;
  149. }];
  150. }
  151. }
  152. - (BOOL)containsKey:(id)key {
  153. return ([self objectForKey:key] != nil);
  154. }
  155. - (NSEnumerator *)keyEnumerator {
  156. return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self
  157. startKey:nil
  158. endKey:nil
  159. isReverse:NO];
  160. }
  161. - (NSEnumerator *)keyEnumeratorFrom:(id)startKey {
  162. return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self
  163. startKey:startKey
  164. endKey:nil
  165. isReverse:NO];
  166. }
  167. - (NSEnumerator *)keyEnumeratorFrom:(id)startKey to:(nullable id)endKey {
  168. return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self
  169. startKey:startKey
  170. endKey:endKey
  171. isReverse:NO];
  172. }
  173. - (NSEnumerator *)reverseKeyEnumerator {
  174. return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self
  175. startKey:nil
  176. endKey:nil
  177. isReverse:YES];
  178. }
  179. - (NSEnumerator *)reverseKeyEnumeratorFrom:(id)startKey {
  180. return [[FSTTreeSortedDictionaryEnumerator alloc] initWithImmutableSortedDictionary:self
  181. startKey:startKey
  182. endKey:nil
  183. isReverse:YES];
  184. }
  185. #pragma mark -
  186. #pragma mark Tree Builder
  187. // Code to efficiently build a red black tree.
  188. typedef struct {
  189. unsigned int bits;
  190. unsigned short count;
  191. unsigned short current;
  192. } Base12List;
  193. unsigned int LogBase2(unsigned int num) {
  194. return (unsigned int)(log(num) / log(2));
  195. }
  196. /**
  197. * Works like an iterator, so it moves to the next bit. Do not call more than list->count times.
  198. * @return whether or not the next bit is a 1 in base {1,2}.
  199. */
  200. BOOL Base12ListNext(Base12List *list) {
  201. BOOL result = !(list->bits & (0x1 << list->current));
  202. list->current--;
  203. return result;
  204. }
  205. static inline unsigned BitMask(int x) {
  206. return (x >= sizeof(unsigned) * CHAR_BIT) ? (unsigned)-1 : (1U << x) - 1;
  207. }
  208. /**
  209. * We represent the base{1,2} number as the combination of a binary number and a number of bits that
  210. * we care about. We iterate backwards, from most significant bit to least, to build up the llrb
  211. * nodes. 0 base 2 => 1 base {1,2}, 1 base 2 => 2 base {1,2}
  212. */
  213. Base12List *NewBase12List(unsigned int length) {
  214. size_t sz = sizeof(Base12List);
  215. Base12List *list = calloc(1, sz);
  216. // Calculate the number of bits that we care about
  217. list->count = (unsigned short)LogBase2(length + 1);
  218. unsigned int mask = BitMask(list->count);
  219. list->bits = (length + 1) & mask;
  220. list->current = list->count - 1;
  221. return list;
  222. }
  223. void FreeBase12List(Base12List *list) {
  224. free(list);
  225. }
  226. + (id<FSTLLRBNode>)buildBalancedTree:(NSArray *)keys
  227. dictionary:(NSDictionary *)dictionary
  228. subArrayStartIndex:(NSUInteger)startIndex
  229. length:(NSUInteger)length {
  230. length = MIN(keys.count - startIndex, length); // Bound length by the actual length of the array
  231. if (length == 0) {
  232. return nil;
  233. } else if (length == 1) {
  234. id key = keys[startIndex];
  235. return [[FSTLLRBValueNode alloc] initWithKey:key
  236. withValue:dictionary[key]
  237. withColor:FSTLLRBColorBlack
  238. withLeft:nil
  239. withRight:nil];
  240. } else {
  241. NSUInteger middle = length / 2;
  242. id<FSTLLRBNode> left = [FSTTreeSortedDictionary buildBalancedTree:keys
  243. dictionary:dictionary
  244. subArrayStartIndex:startIndex
  245. length:middle];
  246. id<FSTLLRBNode> right = [FSTTreeSortedDictionary buildBalancedTree:keys
  247. dictionary:dictionary
  248. subArrayStartIndex:(startIndex + middle + 1)
  249. length:middle];
  250. id key = keys[startIndex + middle];
  251. return [[FSTLLRBValueNode alloc] initWithKey:key
  252. withValue:dictionary[key]
  253. withColor:FSTLLRBColorBlack
  254. withLeft:left
  255. withRight:right];
  256. }
  257. }
  258. + (nullable id<FSTLLRBNode>)rootFrom12List:(Base12List *)base12List
  259. keyList:(NSArray *)keyList
  260. dictionary:(NSDictionary *)dictionary {
  261. __block FSTLLRBValueNode *root = nil;
  262. __block FSTLLRBValueNode *node = nil;
  263. __block NSUInteger index = keyList.count;
  264. void (^buildPennant)(FSTLLRBColor, NSUInteger) = ^(FSTLLRBColor color, NSUInteger chunkSize) {
  265. NSUInteger startIndex = index - chunkSize + 1;
  266. index -= chunkSize;
  267. id key = keyList[index];
  268. FSTLLRBValueNode *childTree = [self buildBalancedTree:keyList
  269. dictionary:dictionary
  270. subArrayStartIndex:startIndex
  271. length:(chunkSize - 1)];
  272. FSTLLRBValueNode *pennant = [[FSTLLRBValueNode alloc] initWithKey:key
  273. withValue:dictionary[key]
  274. withColor:color
  275. withLeft:nil
  276. withRight:childTree];
  277. if (node) {
  278. // This is the only place this property is set.
  279. node.left = pennant;
  280. node = pennant;
  281. } else {
  282. root = pennant;
  283. node = pennant;
  284. }
  285. };
  286. for (int i = 0; i < base12List->count; ++i) {
  287. BOOL isOne = Base12ListNext(base12List);
  288. NSUInteger chunkSize = (NSUInteger)pow(2.0, base12List->count - (i + 1));
  289. if (isOne) {
  290. buildPennant(FSTLLRBColorBlack, chunkSize);
  291. } else {
  292. buildPennant(FSTLLRBColorBlack, chunkSize);
  293. buildPennant(FSTLLRBColorRed, chunkSize);
  294. }
  295. }
  296. return root;
  297. }
  298. /**
  299. * Uses the algorithm linked here:
  300. * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458
  301. */
  302. + (FSTImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary
  303. withComparator:(NSComparator)comparator {
  304. // Steps:
  305. // 0. Sort the array
  306. // 1. Calculate the 1-2 number
  307. // 2. Build From 1-2 number
  308. // 0. for each digit in 1-2 number
  309. // 0. calculate chunk size
  310. // 1. build 1 or 2 pennants of that size
  311. // 2. attach pennants and update node pointer
  312. // 1. return root
  313. NSMutableArray *sortedKeyList = [NSMutableArray arrayWithCapacity:dictionary.count];
  314. [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  315. [sortedKeyList addObject:key];
  316. }];
  317. [sortedKeyList sortUsingComparator:comparator];
  318. [sortedKeyList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  319. if (idx > 0) {
  320. if (comparator(sortedKeyList[idx - 1], obj) != NSOrderedAscending) {
  321. [NSException raise:NSInvalidArgumentException
  322. format:
  323. @"Can't create FSTImmutableSortedDictionary "
  324. @"with keys with same ordering!"];
  325. }
  326. }
  327. }];
  328. Base12List *list = NewBase12List((unsigned int)sortedKeyList.count);
  329. id<FSTLLRBNode> root = [self rootFrom12List:list keyList:sortedKeyList dictionary:dictionary];
  330. FreeBase12List(list);
  331. if (root != nil) {
  332. return [[FSTTreeSortedDictionary alloc] initWithComparator:comparator withRoot:root];
  333. } else {
  334. return [[FSTTreeSortedDictionary alloc] initWithComparator:comparator];
  335. }
  336. }
  337. @end
  338. NS_ASSUME_NONNULL_END