FTreeSortedDictionary.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FTreeSortedDictionary.h"
  17. #import "FLLRBEmptyNode.h"
  18. #import "FLLRBValueNode.h"
  19. #import "FTreeSortedDictionaryEnumerator.h"
  20. typedef void (^fbt_void_nsnumber_int)(NSNumber* color, NSUInteger chunkSize);
  21. @interface FTreeSortedDictionary ()
  22. @property (nonatomic, strong) id<FLLRBNode> root;
  23. @property (nonatomic, copy, readwrite) NSComparator comparator;
  24. @end
  25. @implementation FTreeSortedDictionary
  26. - (id)initWithComparator:(NSComparator)aComparator {
  27. self = [super init];
  28. if (self) {
  29. self.root = [FLLRBEmptyNode emptyNode];
  30. self.comparator = aComparator;
  31. }
  32. return self;
  33. }
  34. - (id)initWithComparator:(NSComparator)aComparator withRoot:(__unsafe_unretained id<FLLRBNode>)aRoot {
  35. self = [super init];
  36. if (self) {
  37. self.root = aRoot;
  38. self.comparator = aComparator;
  39. }
  40. return self;
  41. }
  42. /**
  43. * Returns a copy of the map, with the specified key/value added or replaced.
  44. */
  45. - (FTreeSortedDictionary *) insertKey:(__unsafe_unretained id)aKey withValue:(__unsafe_unretained id)aValue {
  46. return [[FTreeSortedDictionary alloc] initWithComparator:self.comparator
  47. withRoot:[[self.root insertKey:aKey forValue:aValue withComparator:self.comparator]
  48. copyWith:nil
  49. withValue:nil
  50. withColor:BLACK
  51. withLeft:nil
  52. withRight:nil]];
  53. }
  54. - (FTreeSortedDictionary *) removeKey:(__unsafe_unretained id)aKey {
  55. // Remove is somewhat expensive even if the key doesn't exist (the tree does rebalancing and stuff). So avoid it.
  56. if (![self contains:aKey]) {
  57. return self;
  58. } else {
  59. return [[FTreeSortedDictionary alloc]
  60. initWithComparator:self.comparator
  61. withRoot:[[self.root remove:aKey withComparator:self.comparator]
  62. copyWith:nil
  63. withValue:nil
  64. withColor:BLACK
  65. withLeft:nil
  66. withRight:nil]];
  67. }
  68. }
  69. - (id) get:(__unsafe_unretained id) key {
  70. if (key == nil) {
  71. return nil;
  72. }
  73. NSComparisonResult cmp;
  74. id<FLLRBNode> node = self.root;
  75. while(![node isEmpty]) {
  76. cmp = self.comparator(key, node.key);
  77. if(cmp == NSOrderedSame) {
  78. return node.value;
  79. }
  80. else if (cmp == NSOrderedAscending) {
  81. node = node.left;
  82. }
  83. else {
  84. node = node.right;
  85. }
  86. }
  87. return nil;
  88. }
  89. - (id) getPredecessorKey:(__unsafe_unretained id) key {
  90. NSComparisonResult cmp;
  91. id<FLLRBNode> node = self.root;
  92. id<FLLRBNode> rightParent = nil;
  93. while(![node isEmpty]) {
  94. cmp = self.comparator(key, node.key);
  95. if(cmp == NSOrderedSame) {
  96. if(![node.left isEmpty]) {
  97. node = node.left;
  98. while(! [node.right isEmpty]) {
  99. node = node.right;
  100. }
  101. return node.key;
  102. }
  103. else if (rightParent != nil) {
  104. return rightParent.key;
  105. }
  106. else {
  107. return nil;
  108. }
  109. }
  110. else if (cmp == NSOrderedAscending) {
  111. node = node.left;
  112. }
  113. else if (cmp == NSOrderedDescending) {
  114. rightParent = node;
  115. node = node.right;
  116. }
  117. }
  118. @throw [NSException exceptionWithName:@"NonexistentKey" reason:@"getPredecessorKey called with nonexistent key." userInfo:@{@"key": [key description] }];
  119. }
  120. - (BOOL) isEmpty {
  121. return [self.root isEmpty];
  122. }
  123. - (int) count {
  124. return [self.root count];
  125. }
  126. - (id) minKey {
  127. return [self.root minKey];
  128. }
  129. - (id) maxKey {
  130. return [self.root maxKey];
  131. }
  132. - (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block
  133. {
  134. [self enumerateKeysAndObjectsReverse:NO usingBlock:block];
  135. }
  136. - (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block
  137. {
  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) contains:(__unsafe_unretained id)key {
  153. return ([self objectForKey:key] != nil);
  154. }
  155. - (NSEnumerator *) keyEnumerator {
  156. return [[FTreeSortedDictionaryEnumerator alloc]
  157. initWithImmutableSortedDictionary:self startKey:nil isReverse:NO];
  158. }
  159. - (NSEnumerator *) keyEnumeratorFrom:(id)startKey {
  160. return [[FTreeSortedDictionaryEnumerator alloc]
  161. initWithImmutableSortedDictionary:self startKey:startKey isReverse:NO];
  162. }
  163. - (NSEnumerator *) reverseKeyEnumerator {
  164. return [[FTreeSortedDictionaryEnumerator alloc]
  165. initWithImmutableSortedDictionary:self startKey:nil isReverse:YES];
  166. }
  167. - (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey {
  168. return [[FTreeSortedDictionaryEnumerator alloc]
  169. initWithImmutableSortedDictionary:self startKey:startKey isReverse:YES];
  170. }
  171. #pragma mark -
  172. #pragma mark Tree Builder
  173. // Code to efficiently build a RB Tree
  174. typedef struct _base1_2list {
  175. unsigned int bits;
  176. unsigned short count;
  177. unsigned short current;
  178. } Base1_2List;
  179. Base1_2List *base1_2List_new(unsigned int length);
  180. void base1_2List_free(Base1_2List* list);
  181. unsigned int log_base2(unsigned int num);
  182. BOOL base1_2List_next(Base1_2List* list);
  183. unsigned int log_base2(unsigned int num) {
  184. return (unsigned int)(log(num) / log(2));
  185. }
  186. /**
  187. * Works like an iterator, so it moves to the next bit. Do not call more than list->count times.
  188. * @return whether or not the next bit is a 1 in base {1,2}.
  189. */
  190. BOOL base1_2List_next(Base1_2List* list) {
  191. BOOL result = !(list->bits & (0x1 << list->current));
  192. list->current--;
  193. return result;
  194. }
  195. static inline unsigned bit_mask(int x) {
  196. return (x >= sizeof(unsigned) * CHAR_BIT) ? (unsigned) -1 : (1U << x) - 1;
  197. }
  198. /**
  199. * We represent the base{1,2} number as the combination of a binary number and a number of bits that we care about
  200. * We iterate backwards, from most significant bit to least, to build up the llrb nodes. 0 base 2 => 1 base {1,2}, 1 base 2 => 2 base {1,2}
  201. */
  202. Base1_2List *base1_2List_new(unsigned int length) {
  203. size_t sz = sizeof(Base1_2List);
  204. Base1_2List* list = calloc(1, sz);
  205. // Calculate the number of bits that we care about
  206. list->count = (unsigned short)log_base2(length + 1);
  207. unsigned int mask = bit_mask(list->count);
  208. list->bits = (length + 1) & mask;
  209. list->current = list->count - 1;
  210. return list;
  211. }
  212. void base1_2List_free(Base1_2List* list) {
  213. free(list);
  214. }
  215. + (id<FLLRBNode>) buildBalancedTree:(NSArray *)keys dictionary:(NSDictionary *)dictionary subArrayStartIndex:(NSUInteger)startIndex length:(NSUInteger)length {
  216. length = MIN(keys.count - startIndex, length); // Bound length by the actual length of the array
  217. if (length == 0) {
  218. return nil;
  219. } else if (length == 1) {
  220. id key = keys[startIndex];
  221. return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:nil withRight:nil];
  222. } else {
  223. NSUInteger middle = length / 2;
  224. id<FLLRBNode> left = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:startIndex length:middle];
  225. id<FLLRBNode> right = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:(startIndex+middle+1) length:middle];
  226. id key = keys[startIndex + middle];
  227. return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:left withRight:right];
  228. }
  229. }
  230. + (id<FLLRBNode>) rootFrom12List:(Base1_2List *)base1_2List keyList:(NSArray *)keyList dictionary:(NSDictionary *)dictionary {
  231. __block id<FLLRBNode> root = nil;
  232. __block id<FLLRBNode> node = nil;
  233. __block NSUInteger index = keyList.count;
  234. fbt_void_nsnumber_int buildPennant = ^(NSNumber* color, NSUInteger chunkSize) {
  235. NSUInteger startIndex = index - chunkSize + 1;
  236. index -= chunkSize;
  237. id key = keyList[index];
  238. id<FLLRBNode> childTree = [self buildBalancedTree:keyList dictionary:dictionary subArrayStartIndex:startIndex length:(chunkSize - 1)];
  239. id<FLLRBNode> pennant = [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:color withLeft:nil withRight:childTree];
  240. //attachPennant(pennant);
  241. if (node) {
  242. node.left = pennant;
  243. node = pennant;
  244. } else {
  245. root = pennant;
  246. node = pennant;
  247. }
  248. };
  249. for (int i = 0; i < base1_2List->count; ++i) {
  250. BOOL isOne = base1_2List_next(base1_2List);
  251. NSUInteger chunkSize = (NSUInteger)pow(2.0, base1_2List->count - (i + 1));
  252. if (isOne) {
  253. buildPennant(BLACK, chunkSize);
  254. } else {
  255. buildPennant(BLACK, chunkSize);
  256. buildPennant(RED, chunkSize);
  257. }
  258. }
  259. return root;
  260. }
  261. /**
  262. * Uses the algorithm linked here:
  263. * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458
  264. */
  265. + (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator
  266. {
  267. // Steps:
  268. // 0. Sort the array
  269. // 1. Calculate the 1-2 number
  270. // 2. Build From 1-2 number
  271. // 0. for each digit in 1-2 number
  272. // 0. calculate chunk size
  273. // 1. build 1 or 2 pennants of that size
  274. // 2. attach pennants and update node pointer
  275. // 1. return root
  276. NSMutableArray *sortedKeyList = [NSMutableArray arrayWithCapacity:dictionary.count];
  277. [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  278. [sortedKeyList addObject:key];
  279. }];
  280. [sortedKeyList sortUsingComparator:comparator];
  281. [sortedKeyList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  282. if (idx > 0) {
  283. if (comparator(sortedKeyList[idx - 1], obj) != NSOrderedAscending) {
  284. [NSException raise:NSInvalidArgumentException format:@"Can't create FImmutableSortedDictionary with keys with same ordering!"];
  285. }
  286. }
  287. }];
  288. Base1_2List* list = base1_2List_new((unsigned int)sortedKeyList.count);
  289. id<FLLRBNode> root = [self rootFrom12List:list keyList:sortedKeyList dictionary:dictionary];
  290. base1_2List_free(list);
  291. if (root != nil) {
  292. return [[FTreeSortedDictionary alloc] initWithComparator:comparator withRoot:root];
  293. } else {
  294. return [[FTreeSortedDictionary alloc] initWithComparator:comparator];
  295. }
  296. }
  297. @end