FSTLLRBValueNode.m 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #import "Firestore/third_party/Immutable/FSTLLRBValueNode.h"
  2. #import "Firestore/Source/Util/FSTAssert.h"
  3. #import "Firestore/third_party/Immutable/FSTLLRBEmptyNode.h"
  4. NS_ASSUME_NONNULL_BEGIN
  5. @interface FSTLLRBValueNode ()
  6. @property(nonatomic, assign) FSTLLRBColor color;
  7. @property(nonatomic, assign) NSUInteger count;
  8. @property(nonatomic, strong) id key;
  9. @property(nonatomic, strong) id value;
  10. @property(nonatomic, strong) id<FSTLLRBNode> right;
  11. @end
  12. @implementation FSTLLRBValueNode
  13. - (NSString *)colorDescription {
  14. NSString *color = @"unspecified";
  15. if (self.color == FSTLLRBColorRed) {
  16. color = @"red";
  17. } else if (self.color == FSTLLRBColorBlack) {
  18. color = @"black";
  19. }
  20. return color;
  21. }
  22. - (NSString *)description {
  23. NSString *color = self.colorDescription;
  24. return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", self.key, self.value, color];
  25. }
  26. // Designated initializer.
  27. - (instancetype)initWithKey:(id _Nullable)aKey
  28. withValue:(id _Nullable)aValue
  29. withColor:(FSTLLRBColor)aColor
  30. withLeft:(id<FSTLLRBNode> _Nullable)aLeft
  31. withRight:(id<FSTLLRBNode> _Nullable)aRight {
  32. self = [super init];
  33. if (self) {
  34. _key = aKey;
  35. _value = aValue;
  36. _color = aColor != FSTLLRBColorUnspecified ? aColor : FSTLLRBColorRed;
  37. _left = aLeft != nil ? aLeft : [FSTLLRBEmptyNode emptyNode];
  38. _right = aRight != nil ? aRight : [FSTLLRBEmptyNode emptyNode];
  39. _count = NSNotFound;
  40. }
  41. return self;
  42. }
  43. - (instancetype)copyWith:(id _Nullable)aKey
  44. withValue:(id _Nullable)aValue
  45. withColor:(FSTLLRBColor)aColor
  46. withLeft:(id<FSTLLRBNode> _Nullable)aLeft
  47. withRight:(id<FSTLLRBNode> _Nullable)aRight {
  48. return [[FSTLLRBValueNode alloc]
  49. initWithKey:(aKey != nil) ? aKey : self.key
  50. withValue:(aValue != nil) ? aValue : self.value
  51. withColor:(aColor != FSTLLRBColorUnspecified) ? aColor : self.color
  52. withLeft:(aLeft != nil) ? aLeft : self.left
  53. withRight:(aRight != nil) ? aRight : self.right];
  54. }
  55. - (void)setLeft:(nullable id<FSTLLRBNode>)left {
  56. // Setting the left node should be only done by the builder, so doing it after someone has
  57. // memoized count is an error.
  58. FSTAssert(_count == NSNotFound, @"Can't update left node after using count");
  59. _left = left;
  60. }
  61. - (NSUInteger)count {
  62. if (_count == NSNotFound) {
  63. _count = _left.count + 1 + _right.count;
  64. }
  65. return _count;
  66. }
  67. - (BOOL)isEmpty {
  68. return NO;
  69. }
  70. /**
  71. * Early terminates if action returns YES.
  72. *
  73. * @return The first truthy value returned by action, or the last falsey value returned by action.
  74. */
  75. - (BOOL)inorderTraversal:(BOOL (^)(id key, id value))action {
  76. return [self.left inorderTraversal:action] || action(self.key, self.value) ||
  77. [self.right inorderTraversal:action];
  78. }
  79. - (BOOL)reverseTraversal:(BOOL (^)(id key, id value))action {
  80. return [self.right reverseTraversal:action] || action(self.key, self.value) ||
  81. [self.left reverseTraversal:action];
  82. }
  83. - (id<FSTLLRBNode>)min {
  84. if ([self.left isEmpty]) {
  85. return self;
  86. } else {
  87. return [self.left min];
  88. }
  89. }
  90. - (nullable id)minKey {
  91. return [[self min] key];
  92. }
  93. - (nullable id)maxKey {
  94. if ([self.right isEmpty]) {
  95. return self.key;
  96. } else {
  97. return [self.right maxKey];
  98. }
  99. }
  100. - (id<FSTLLRBNode>)insertKey:(id)aKey forValue:(id)aValue withComparator:(NSComparator)aComparator {
  101. NSComparisonResult cmp = aComparator(aKey, self.key);
  102. FSTLLRBValueNode *n = self;
  103. if (cmp == NSOrderedAscending) {
  104. n = [n copyWith:nil
  105. withValue:nil
  106. withColor:FSTLLRBColorUnspecified
  107. withLeft:[n.left insertKey:aKey forValue:aValue withComparator:aComparator]
  108. withRight:nil];
  109. } else if (cmp == NSOrderedSame) {
  110. n = [n copyWith:nil
  111. withValue:aValue
  112. withColor:FSTLLRBColorUnspecified
  113. withLeft:nil
  114. withRight:nil];
  115. } else {
  116. n = [n copyWith:nil
  117. withValue:nil
  118. withColor:FSTLLRBColorUnspecified
  119. withLeft:nil
  120. withRight:[n.right insertKey:aKey forValue:aValue withComparator:aComparator]];
  121. }
  122. return [n fixUp];
  123. }
  124. - (id<FSTLLRBNode>)removeMin {
  125. if ([self.left isEmpty]) {
  126. return [FSTLLRBEmptyNode emptyNode];
  127. }
  128. FSTLLRBValueNode *n = self;
  129. if (![n.left isRed] && ![n.left.left isRed]) {
  130. n = [n moveRedLeft];
  131. }
  132. n = [n copyWith:nil
  133. withValue:nil
  134. withColor:FSTLLRBColorUnspecified
  135. withLeft:[(FSTLLRBValueNode *)n.left removeMin]
  136. withRight:nil];
  137. return [n fixUp];
  138. }
  139. - (id<FSTLLRBNode>)fixUp {
  140. FSTLLRBValueNode *n = self;
  141. if ([n.right isRed] && ![n.left isRed]) n = [n rotateLeft];
  142. if ([n.left isRed] && [n.left.left isRed]) n = [n rotateRight];
  143. if ([n.left isRed] && [n.right isRed]) n = [n colorFlip];
  144. return n;
  145. }
  146. - (FSTLLRBValueNode *)moveRedLeft {
  147. FSTLLRBValueNode *n = [self colorFlip];
  148. if ([n.right.left isRed]) {
  149. n = [n copyWith:nil
  150. withValue:nil
  151. withColor:FSTLLRBColorUnspecified
  152. withLeft:nil
  153. withRight:[(FSTLLRBValueNode *)n.right rotateRight]];
  154. n = [n rotateLeft];
  155. n = [n colorFlip];
  156. }
  157. return n;
  158. }
  159. - (FSTLLRBValueNode *)moveRedRight {
  160. FSTLLRBValueNode *n = [self colorFlip];
  161. if ([n.left.left isRed]) {
  162. n = [n rotateRight];
  163. n = [n colorFlip];
  164. }
  165. return n;
  166. }
  167. - (id<FSTLLRBNode>)rotateLeft {
  168. id<FSTLLRBNode> nl = [self copyWith:nil
  169. withValue:nil
  170. withColor:FSTLLRBColorRed
  171. withLeft:nil
  172. withRight:self.right.left];
  173. return [self.right copyWith:nil withValue:nil withColor:self.color withLeft:nl withRight:nil];
  174. }
  175. - (id<FSTLLRBNode>)rotateRight {
  176. id<FSTLLRBNode> nr = [self copyWith:nil
  177. withValue:nil
  178. withColor:FSTLLRBColorRed
  179. withLeft:self.left.right
  180. withRight:nil];
  181. return [self.left copyWith:nil withValue:nil withColor:self.color withLeft:nil withRight:nr];
  182. }
  183. - (id<FSTLLRBNode>)colorFlip {
  184. FSTLLRBColor color = self.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack;
  185. FSTLLRBColor leftColor =
  186. self.left.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack;
  187. FSTLLRBColor rightColor =
  188. self.right.color == FSTLLRBColorBlack ? FSTLLRBColorRed : FSTLLRBColorBlack;
  189. id<FSTLLRBNode> nleft =
  190. [self.left copyWith:nil withValue:nil withColor:leftColor withLeft:nil withRight:nil];
  191. id<FSTLLRBNode> nright =
  192. [self.right copyWith:nil withValue:nil withColor:rightColor withLeft:nil withRight:nil];
  193. return [self copyWith:nil withValue:nil withColor:color withLeft:nleft withRight:nright];
  194. }
  195. - (id<FSTLLRBNode>)remove:(id)aKey withComparator:(NSComparator)comparator {
  196. id<FSTLLRBNode> smallest;
  197. FSTLLRBValueNode *n = self;
  198. if (comparator(aKey, n.key) == NSOrderedAscending) {
  199. if (![n.left isEmpty] && ![n.left isRed] && ![n.left.left isRed]) {
  200. n = [n moveRedLeft];
  201. }
  202. n = [n copyWith:nil
  203. withValue:nil
  204. withColor:FSTLLRBColorUnspecified
  205. withLeft:[n.left remove:aKey withComparator:comparator]
  206. withRight:nil];
  207. } else {
  208. if ([n.left isRed]) {
  209. n = [n rotateRight];
  210. }
  211. if (![n.right isEmpty] && ![n.right isRed] && ![n.right.left isRed]) {
  212. n = [n moveRedRight];
  213. }
  214. if (comparator(aKey, n.key) == NSOrderedSame) {
  215. if ([n.right isEmpty]) {
  216. return [FSTLLRBEmptyNode emptyNode];
  217. } else {
  218. smallest = [n.right min];
  219. n = [n copyWith:smallest.key
  220. withValue:smallest.value
  221. withColor:FSTLLRBColorUnspecified
  222. withLeft:nil
  223. withRight:[(FSTLLRBValueNode *)n.right removeMin]];
  224. }
  225. }
  226. n = [n copyWith:nil
  227. withValue:nil
  228. withColor:FSTLLRBColorUnspecified
  229. withLeft:nil
  230. withRight:[n.right remove:aKey withComparator:comparator]];
  231. }
  232. return [n fixUp];
  233. }
  234. - (BOOL)isRed {
  235. return self.color == FSTLLRBColorRed;
  236. }
  237. - (BOOL)checkMaxDepth {
  238. int blackDepth = [self check];
  239. if (pow(2.0, blackDepth) <= ([self count] + 1)) {
  240. return YES;
  241. } else {
  242. return NO;
  243. }
  244. }
  245. - (int)check {
  246. int blackDepth = 0;
  247. if ([self isRed] && [self.left isRed]) {
  248. @throw
  249. [[NSException alloc] initWithName:@"check" reason:@"Red node has a red child" userInfo:nil];
  250. }
  251. if ([self.right isRed]) {
  252. @throw [[NSException alloc] initWithName:@"check" reason:@"Right child is red" userInfo:nil];
  253. }
  254. blackDepth = [self.left check];
  255. if (blackDepth != [self.right check]) {
  256. NSString *err =
  257. [NSString stringWithFormat:@"(%@ -> %@)blackDepth: %d ; self.right check: %d", self.value,
  258. self.colorDescription, blackDepth, [self.right check]];
  259. @throw [[NSException alloc] initWithName:@"check" reason:err userInfo:nil];
  260. } else {
  261. int ret = blackDepth + ([self isRed] ? 0 : 1);
  262. return ret;
  263. }
  264. }
  265. @end
  266. NS_ASSUME_NONNULL_END