FIndexedNode.m 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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 "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h"
  17. #import "FirebaseDatabase/Sources/FIndex.h"
  18. #import "FirebaseDatabase/Sources/FKeyIndex.h"
  19. #import "FirebaseDatabase/Sources/FPriorityIndex.h"
  20. #import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h"
  21. #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h"
  22. static FImmutableSortedSet *FALLBACK_INDEX;
  23. @interface FIndexedNode ()
  24. @property(nonatomic, strong) id<FNode> node;
  25. /**
  26. * The indexed set is initialized lazily to prevent creation when it is not
  27. * needed
  28. */
  29. @property(nonatomic, strong) FImmutableSortedSet *indexed;
  30. @property(nonatomic, strong) id<FIndex> index;
  31. @end
  32. @implementation FIndexedNode
  33. + (FImmutableSortedSet *)fallbackIndex {
  34. static FImmutableSortedSet *fallbackIndex;
  35. static dispatch_once_t once;
  36. dispatch_once(&once, ^{
  37. fallbackIndex = [[FImmutableSortedSet alloc] init];
  38. });
  39. return fallbackIndex;
  40. }
  41. + (FIndexedNode *)indexedNodeWithNode:(id<FNode>)node {
  42. return [[FIndexedNode alloc] initWithNode:node
  43. index:[FPriorityIndex priorityIndex]];
  44. }
  45. + (FIndexedNode *)indexedNodeWithNode:(id<FNode>)node index:(id<FIndex>)index {
  46. return [[FIndexedNode alloc] initWithNode:node index:index];
  47. }
  48. - (id)initWithNode:(id<FNode>)node index:(id<FIndex>)index {
  49. // Initialize indexed lazily
  50. return [self initWithNode:node index:index indexed:nil];
  51. }
  52. - (id)initWithNode:(id<FNode>)node
  53. index:(id<FIndex>)index
  54. indexed:(FImmutableSortedSet *)indexed {
  55. self = [super init];
  56. if (self != nil) {
  57. self->_node = node;
  58. self->_index = index;
  59. self->_indexed = indexed;
  60. }
  61. return self;
  62. }
  63. - (void)ensureIndexed {
  64. if (!self.indexed) {
  65. if ([self.index isEqual:[FKeyIndex keyIndex]]) {
  66. self.indexed = [FIndexedNode fallbackIndex];
  67. } else {
  68. __block BOOL sawChild = NO;
  69. [self.node enumerateChildrenUsingBlock:^(
  70. NSString *key, id<FNode> node, BOOL *stop) {
  71. sawChild = sawChild || [self.index isDefinedOn:node];
  72. *stop = sawChild;
  73. }];
  74. if (sawChild) {
  75. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  76. [self.node enumerateChildrenUsingBlock:^(
  77. NSString *key, id<FNode> node, BOOL *stop) {
  78. FNamedNode *namedNode =
  79. [[FNamedNode alloc] initWithName:key andNode:node];
  80. dict[namedNode] = [NSNull null];
  81. }];
  82. // Make sure to assign index here, because the comparator will
  83. // be retained and using self will cause a cycle
  84. id<FIndex> index = self.index;
  85. self.indexed = [FImmutableSortedSet
  86. setWithKeysFromDictionary:dict
  87. comparator:^NSComparisonResult(
  88. FNamedNode *namedNode1,
  89. FNamedNode *namedNode2) {
  90. return [index compareNamedNode:namedNode1
  91. toNamedNode:namedNode2];
  92. }];
  93. } else {
  94. self.indexed = [FIndexedNode fallbackIndex];
  95. }
  96. }
  97. }
  98. }
  99. - (BOOL)hasIndex:(id<FIndex>)index {
  100. return [self.index isEqual:index];
  101. }
  102. - (FIndexedNode *)updateChild:(NSString *)key
  103. withNewChild:(id<FNode>)newChildNode {
  104. id<FNode> newNode = [self.node updateImmediateChild:key
  105. withNewChild:newChildNode];
  106. if (self.indexed == [FIndexedNode fallbackIndex] &&
  107. ![self.index isDefinedOn:newChildNode]) {
  108. // doesn't affect the index, no need to create an index
  109. return [[FIndexedNode alloc] initWithNode:newNode
  110. index:self.index
  111. indexed:[FIndexedNode fallbackIndex]];
  112. } else if (!self.indexed || self.indexed == [FIndexedNode fallbackIndex]) {
  113. // No need to index yet, index lazily
  114. return [[FIndexedNode alloc] initWithNode:newNode index:self.index];
  115. } else {
  116. id<FNode> oldChild = [self.node getImmediateChild:key];
  117. FImmutableSortedSet *newIndexed = [self.indexed
  118. removeObject:[FNamedNode nodeWithName:key node:oldChild]];
  119. if (![newChildNode isEmpty]) {
  120. newIndexed = [newIndexed
  121. addObject:[FNamedNode nodeWithName:key node:newChildNode]];
  122. }
  123. return [[FIndexedNode alloc] initWithNode:newNode
  124. index:self.index
  125. indexed:newIndexed];
  126. }
  127. }
  128. - (FIndexedNode *)updatePriority:(id<FNode>)priority {
  129. return
  130. [[FIndexedNode alloc] initWithNode:[self.node updatePriority:priority]
  131. index:self.index
  132. indexed:self.indexed];
  133. }
  134. - (FNamedNode *)firstChild {
  135. if (![self.node isKindOfClass:[FChildrenNode class]]) {
  136. return nil;
  137. } else {
  138. [self ensureIndexed];
  139. if (self.indexed == [FIndexedNode fallbackIndex]) {
  140. return [((FChildrenNode *)self.node) firstChild];
  141. } else {
  142. return self.indexed.firstObject;
  143. }
  144. }
  145. }
  146. - (FNamedNode *)lastChild {
  147. if (![self.node isKindOfClass:[FChildrenNode class]]) {
  148. return nil;
  149. } else {
  150. [self ensureIndexed];
  151. if (self.indexed == [FIndexedNode fallbackIndex]) {
  152. return [((FChildrenNode *)self.node) lastChild];
  153. } else {
  154. return self.indexed.lastObject;
  155. }
  156. }
  157. }
  158. - (NSString *)predecessorForChildKey:(NSString *)childKey
  159. childNode:(id<FNode>)childNode
  160. index:(id<FIndex>)index {
  161. if (![self.index isEqual:index]) {
  162. [NSException raise:NSInvalidArgumentException
  163. format:@"Index not available in IndexedNode!"];
  164. }
  165. [self ensureIndexed];
  166. if (self.indexed == [FIndexedNode fallbackIndex]) {
  167. return [self.node predecessorChildKey:childKey];
  168. } else {
  169. FNamedNode *node = [self.indexed
  170. predecessorEntry:[FNamedNode nodeWithName:childKey node:childNode]];
  171. return node.name;
  172. }
  173. }
  174. - (void)enumerateChildrenReverse:(BOOL)reverse
  175. usingBlock:
  176. (void (^)(NSString *, id<FNode>, BOOL *))block {
  177. [self ensureIndexed];
  178. if (self.indexed == [FIndexedNode fallbackIndex]) {
  179. [self.node enumerateChildrenReverse:reverse usingBlock:block];
  180. } else {
  181. [self.indexed
  182. enumerateObjectsReverse:reverse
  183. usingBlock:^(FNamedNode *namedNode, BOOL *stop) {
  184. block(namedNode.name, namedNode.node, stop);
  185. }];
  186. }
  187. }
  188. - (NSEnumerator *)childEnumerator {
  189. [self ensureIndexed];
  190. if (self.indexed == [FIndexedNode fallbackIndex]) {
  191. return [self.node childEnumerator];
  192. } else {
  193. return [self.indexed objectEnumerator];
  194. }
  195. }
  196. @end