| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h"
- #import "FirebaseDatabase/Sources/Constants/FConstants.h"
- #import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h"
- #import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h"
- #import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h"
- #import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h"
- #import "FirebaseDatabase/Sources/Utilities/FUtilities.h"
- #import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h"
- @interface FLeafNode ()
- @property(nonatomic, strong) id<FNode> priorityNode;
- @property(nonatomic, strong) NSString *lazyHash;
- @end
- @implementation FLeafNode
- @synthesize value;
- @synthesize priorityNode;
- - (id)initWithValue:(id)aValue {
- self = [super init];
- if (self) {
- self.value = aValue;
- self.priorityNode = [FEmptyNode emptyNode];
- }
- return self;
- }
- - (id)initWithValue:(id)aValue withPriority:(id<FNode>)aPriority {
- self = [super init];
- if (self) {
- self.value = aValue;
- [FSnapshotUtilities validatePriorityNode:aPriority];
- self.priorityNode = aPriority;
- }
- return self;
- }
- #pragma mark -
- #pragma mark FNode methods
- - (BOOL)isLeafNode {
- return YES;
- }
- - (id<FNode>)getPriority {
- return self.priorityNode;
- }
- - (id<FNode>)updatePriority:(id<FNode>)aPriority {
- return [[FLeafNode alloc] initWithValue:self.value withPriority:aPriority];
- }
- - (id<FNode>)getImmediateChild:(NSString *)childName {
- if ([childName isEqualToString:@".priority"]) {
- return self.priorityNode;
- } else {
- return [FEmptyNode emptyNode];
- }
- }
- - (id<FNode>)getChild:(FPath *)path {
- if (path.getFront == nil) {
- return self;
- } else if ([[path getFront] isEqualToString:@".priority"]) {
- return [self getPriority];
- } else {
- return [FEmptyNode emptyNode];
- }
- }
- - (BOOL)hasChild:(NSString *)childName {
- return
- [childName isEqualToString:@".priority"] && ![self getPriority].isEmpty;
- }
- - (NSString *)predecessorChildKey:(NSString *)childKey {
- return nil;
- }
- - (id<FNode>)updateImmediateChild:(NSString *)childName
- withNewChild:(id<FNode>)newChildNode {
- if ([childName isEqualToString:@".priority"]) {
- return [self updatePriority:newChildNode];
- } else if (newChildNode.isEmpty) {
- return self;
- } else {
- FChildrenNode *childrenNode = [[FChildrenNode alloc] init];
- childrenNode = [childrenNode updateImmediateChild:childName
- withNewChild:newChildNode];
- childrenNode = [childrenNode updatePriority:self.priorityNode];
- return childrenNode;
- }
- }
- - (id<FNode>)updateChild:(FPath *)path withNewChild:(id<FNode>)newChildNode {
- NSString *front = [path getFront];
- if (front == nil) {
- return newChildNode;
- } else if (newChildNode.isEmpty && ![front isEqualToString:@".priority"]) {
- return self;
- } else {
- NSAssert(![front isEqualToString:@".priority"] || path.length == 1,
- @".priority must be the last token in a path.");
- return [self updateImmediateChild:front
- withNewChild:[[FEmptyNode emptyNode]
- updateChild:[path popFront]
- withNewChild:newChildNode]];
- }
- }
- - (id)val {
- return [self valForExport:NO];
- }
- - (id)valForExport:(BOOL)exp {
- if (exp && !self.getPriority.isEmpty) {
- return @{
- kPayloadValue : self.value,
- kPayloadPriority : [[self getPriority] val]
- };
- } else {
- return self.value;
- }
- }
- - (BOOL)isEqual:(id<FNode>)other {
- if (other == self) {
- return YES;
- } else if (other.isLeafNode) {
- FLeafNode *otherLeaf = other;
- if ([FUtilities getJavascriptType:self.value] !=
- [FUtilities getJavascriptType:otherLeaf.value]) {
- return NO;
- }
- return [otherLeaf.value isEqual:self.value] &&
- [otherLeaf.priorityNode isEqual:self.priorityNode];
- } else {
- return NO;
- }
- }
- - (NSUInteger)hash {
- return [self.value hash] * 17 + self.priorityNode.hash;
- }
- - (id<FNode>)withIndex:(id<FIndex>)index {
- return self;
- }
- - (BOOL)isIndexed:(id<FIndex>)index {
- return YES;
- }
- - (BOOL)isEmpty {
- return NO;
- }
- - (int)numChildren {
- return 0;
- }
- - (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id<FNode>,
- BOOL *))block {
- // Nothing to iterate over
- }
- - (void)enumerateChildrenReverse:(BOOL)reverse
- usingBlock:
- (void (^)(NSString *, id<FNode>, BOOL *))block {
- // Nothing to iterate over
- }
- - (NSEnumerator *)childEnumerator {
- // Nothing to iterate over
- return [@[] objectEnumerator];
- }
- - (NSString *)dataHash {
- if (self.lazyHash == nil) {
- NSMutableString *toHash = [[NSMutableString alloc] init];
- [FSnapshotUtilities
- appendHashRepresentationForLeafNode:self
- toString:toHash
- hashVersion:FDataHashVersionV1];
- self.lazyHash = [FStringUtilities base64EncodedSha1:toHash];
- }
- return self.lazyHash;
- }
- - (NSComparisonResult)compare:(id<FNode>)other {
- if (other == [FEmptyNode emptyNode]) {
- return NSOrderedDescending;
- } else if ([other isKindOfClass:[FChildrenNode class]]) {
- return NSOrderedAscending;
- } else {
- NSAssert(other.isLeafNode, @"Compared against unknown type of node.");
- return [self compareToLeafNode:(FLeafNode *)other];
- }
- }
- + (NSArray *)valueTypeOrder {
- static NSArray *valueOrder = nil;
- static dispatch_once_t once;
- dispatch_once(&once, ^{
- valueOrder = @[
- kJavaScriptObject, kJavaScriptBoolean, kJavaScriptNumber,
- kJavaScriptString
- ];
- });
- return valueOrder;
- }
- - (NSComparisonResult)compareToLeafNode:(FLeafNode *)other {
- NSString *thisLeafType = [FUtilities getJavascriptType:self.value];
- NSString *otherLeafType = [FUtilities getJavascriptType:other.value];
- NSUInteger thisIndex =
- [[FLeafNode valueTypeOrder] indexOfObject:thisLeafType];
- NSUInteger otherIndex =
- [[FLeafNode valueTypeOrder] indexOfObject:otherLeafType];
- assert(thisIndex >= 0 && otherIndex >= 0);
- if (otherIndex == thisIndex) {
- // Same type. Compare values.
- if (thisLeafType == kJavaScriptObject) {
- // Deferred value nodes are all equal, but we should also never get
- // to this point...
- return NSOrderedSame;
- } else if (thisLeafType == kJavaScriptString) {
- return [self.value compare:other.value options:NSLiteralSearch];
- } else {
- return [self.value compare:other.value];
- }
- } else {
- return thisIndex > otherIndex ? NSOrderedDescending
- : NSOrderedAscending;
- }
- }
- - (NSString *)description {
- return [[self valForExport:YES] description];
- }
- - (void)forEachChildDo:(fbt_bool_nsstring_node)action {
- // There are no children, so there is nothing to do.
- return;
- }
- @end
|