修改pods

This commit is contained in:
2025-09-20 17:13:38 +08:00
parent 7787b3ee30
commit 28ff2b0264
5251 changed files with 345029 additions and 285168 deletions

View File

@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
/** @typedef FIRTokenCallback
@brief The type of block which gets called when a token is ready.
*/
typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error)
typedef void (^FIRTokenCallback)(NSString *_Nullable_result token, NSError *_Nullable error)
NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");
/// Common methods for Auth interoperability.
@@ -34,7 +34,7 @@ NS_SWIFT_NAME(AuthInterop)
/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired.
- (void)getTokenForcingRefresh:(BOOL)forceRefresh
withCallback:
(void (^)(NSString *_Nullable token, NSError *_Nullable error))callback
(void (^)(NSString *_Nullable_result token, NSError *_Nullable error))callback
NS_SWIFT_NAME(getToken(forcingRefresh:completion:));
/// Get the current Auth user's UID. Returns nil if there is no user signed in.

View File

@@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRAPPINTERNAL_H
#define FIREBASECORE_FIRAPPINTERNAL_H
#import <FirebaseCore/FIRApp.h>
@class FIRComponentContainer;
@@ -40,8 +43,26 @@ extern NSString *const kFIRAppNameKey;
extern NSString *const kFIRGoogleAppIDKey;
extern NSString *const kFirebaseCoreErrorDomain;
/** The `UserDefaults` suite name for `FirebaseCore`, for those storage locations that use it. */
extern NSString *const kFirebaseCoreDefaultsSuiteName;
/**
* Keys for the strings in the plist file.
*/
extern NSString *const kFIRAPIKey;
extern NSString *const kFIRTrackingID;
extern NSString *const kFIRGoogleAppID;
extern NSString *const kFIRClientID;
extern NSString *const kFIRGCMSenderID;
extern NSString *const kFIRAndroidClientID;
extern NSString *const kFIRDatabaseURL;
extern NSString *const kFIRStorageBucket;
extern NSString *const kFIRBundleID;
extern NSString *const kFIRProjectID;
/**
* Keys for the plist file name
*/
extern NSString *const kServiceInfoFileName;
extern NSString *const kServiceInfoFileType;
/**
* The format string for the `UserDefaults` key used for storing the data collection enabled flag.
@@ -157,3 +178,5 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey;
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRAPPINTERNAL_H

View File

@@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRCOMPONENT_H
#define FIREBASECORE_FIRCOMPONENT_H
#import <Foundation/Foundation.h>
@class FIRApp;
@@ -32,8 +35,6 @@ typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *contain
BOOL *isCacheable)
NS_SWIFT_NAME(ComponentCreationBlock);
@class FIRDependency;
/// Describes the timing of instantiation. Note: new components should default to lazy unless there
/// is a strong reason to be eager.
typedef NS_ENUM(NSInteger, FIRInstantiationTiming) {
@@ -52,9 +53,6 @@ NS_SWIFT_NAME(Component)
/// The timing of instantiation.
@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming;
/// An array of dependencies for the component.
@property(nonatomic, copy, readonly) NSArray<FIRDependency *> *dependencies;
/// A block to instantiate an instance of the component with the appropriate dependencies.
@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock;
@@ -72,14 +70,12 @@ NS_SWIFT_NAME(init(_:creationBlock:));
/// @param protocol - The protocol describing functionality provided by the component.
/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's
/// a good reason to be instantiated earlier.
/// @param dependencies - Any dependencies the `implementingClass` has, optional or required.
/// @param creationBlock - A block to instantiate the component with a container, and if
/// @return A component that can be registered with the component container.
+ (instancetype)componentWithProtocol:(Protocol *)protocol
instantiationTiming:(FIRInstantiationTiming)instantiationTiming
dependencies:(NSArray<FIRDependency *> *)dependencies
creationBlock:(FIRComponentCreationBlock)creationBlock
NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:));
NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:));
// clang-format on
@@ -89,3 +85,5 @@ NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:));
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRCOMPONENT_H

View File

@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRCOMPONENTCONTAINER_H
#define FIREBASECORE_FIRCOMPONENTCONTAINER_H
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@@ -43,3 +47,5 @@ NS_SWIFT_NAME(FirebaseComponentContainer)
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRCOMPONENTCONTAINER_H

View File

@@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRCOMPONENTTYPE_H
#define FIREBASECORE_FIRCOMPONENTTYPE_H
#import <Foundation/Foundation.h>
@class FIRComponentContainer;
@@ -33,3 +36,5 @@ NS_SWIFT_NAME(ComponentType)
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRCOMPONENTTYPE_H

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2018 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// A dependency on a specific protocol's functionality.
NS_SWIFT_NAME(Dependency)
@interface FIRDependency : NSObject
/// The protocol describing functionality being depended on.
@property(nonatomic, strong, readonly) Protocol *protocol;
/// A flag to specify if the dependency is required or not.
@property(nonatomic, readonly) BOOL isRequired;
/// Initializes a dependency that is required. Calls `init(protocol:isRequired:)` with true for
/// the required parameter.
/// Creates a required dependency on the specified protocol's functionality.
+ (instancetype)dependencyWithProtocol:(Protocol *)protocol;
/// Creates a dependency on the specified protocol's functionality and specify if it's required for
/// the class's functionality.
+ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required;
/// Use `init(withProtocol:isRequired:)` instead.
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FIREBASECORE_FIRHEARTBEATLOGGER_H
#define FIREBASECORE_FIRHEARTBEATLOGGER_H
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@@ -30,19 +33,24 @@ typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) {
FIRDailyHeartbeatCodeSome = 2,
};
NS_SWIFT_SENDABLE
@protocol FIRHeartbeatLoggerProtocol <NSObject>
/// Asynchronously logs a heartbeat.
- (void)log;
#ifndef FIREBASE_BUILD_CMAKE
/// Flushes heartbeats from storage into a structured payload of heartbeats.
- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload;
#endif // FIREBASE_BUILD_CMAKE
/// Gets the heartbeat code for today.
- (FIRDailyHeartbeatCode)heartbeatCodeForToday;
#ifndef FIREBASE_BUILD_CMAKE
/// Returns the header value for the heartbeat logger via the given completion handler..
- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler
API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0));
/// Return the header value for the heartbeat logger.
- (NSString *_Nullable)headerValue;
#endif // FIREBASE_BUILD_CMAKE
@end
#ifndef FIREBASE_BUILD_CMAKE
@@ -68,13 +76,23 @@ NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *he
- (void)log;
#ifndef FIREBASE_BUILD_CMAKE
/// Flushes heartbeats from storage into a structured payload of heartbeats.
/// Synchronously flushes heartbeats from storage into a structured payload of heartbeats.
///
/// This API is for clients using platform logging V2.
///
/// @note This API is thread-safe.
/// @return A payload of heartbeats.
- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload;
/// Asynchronously flushes heartbeats from storage into a structured payload of heartbeats.
///
/// This API is for clients using platform logging V2.
///
/// @note This API is thread-safe.
/// @param completionHandler A completion handler to process the flushed payload of heartbeats.
- (void)flushHeartbeatsIntoPayloadWithCompletionHandler:
(void (^)(FIRHeartbeatsPayload *))completionHandler
API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0));
#endif // FIREBASE_BUILD_CMAKE
/// Gets today's corresponding heartbeat code.
@@ -88,3 +106,5 @@ NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *he
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRHEARTBEATLOGGER_H

View File

@@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRLIBRARY_H
#define FIREBASECORE_FIRLIBRARY_H
#ifndef FIRLibrary_h
#define FIRLibrary_h
@@ -32,13 +35,10 @@ NS_SWIFT_NAME(Library)
/// FirebaseApp and participate in dependency resolution and injection.
+ (NSArray<FIRComponent *> *)componentsToRegister;
@optional
/// Implement this method if the library needs notifications for lifecycle events. This method is
/// called when the developer calls `FirebaseApp.configure()`.
+ (void)configureWithApp:(FIRApp *)app;
@end
NS_ASSUME_NONNULL_END
#endif /* FIRLibrary_h */
#endif // FIREBASECORE_FIRLIBRARY_H

View File

@@ -14,9 +14,12 @@
* limitations under the License.
*/
#ifndef FIREBASECORE_FIRLOGGER_H
#define FIREBASECORE_FIRLOGGER_H
#import <Foundation/Foundation.h>
#import <FirebaseCore/FIRLoggerLevel.h>
typedef NS_ENUM(NSInteger, FIRLoggerLevel);
NS_ASSUME_NONNULL_BEGIN
@@ -25,10 +28,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
typedef NSString *const FIRLoggerService;
extern FIRLoggerService kFIRLoggerAnalytics;
extern FIRLoggerService kFIRLoggerCrash;
extern FIRLoggerService kFIRLoggerCore;
extern FIRLoggerService kFIRLoggerRemoteConfig;
extern NSString *const kFIRLoggerAnalytics;
extern NSString *const kFIRLoggerCrash;
extern NSString *const kFIRLoggerCore;
extern NSString *const kFIRLoggerRemoteConfig;
/**
* The key used to store the logger's error count.
@@ -64,6 +67,11 @@ FIRLoggerLevel FIRGetLoggerLevel(void);
*/
void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
void FIRSetLoggerLevelNotice(void);
void FIRSetLoggerLevelWarning(void);
void FIRSetLoggerLevelError(void);
void FIRSetLoggerLevelDebug(void);
/**
* Checks if the specified logger level is loggable given the current settings.
* (required) log level (one of the FirebaseLoggerLevel enum values).
@@ -71,6 +79,11 @@ void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel);
*/
BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent);
BOOL FIRIsLoggableLevelNotice(void);
BOOL FIRIsLoggableLevelWarning(void);
BOOL FIRIsLoggableLevelError(void);
BOOL FIRIsLoggableLevelDebug(void);
/**
* Logs a message to the Xcode console and the device log. If running from AppStore, will
* not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming.
@@ -85,7 +98,7 @@ BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent);
* string.
*/
extern void FIRLogBasic(FIRLoggerLevel level,
FIRLoggerService service,
NSString *category,
NSString *messageCode,
NSString *message,
// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable
@@ -110,43 +123,51 @@ extern void FIRLogBasic(FIRLoggerLevel level,
* Example usage:
* FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name);
*/
extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...)
extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...)
NS_FORMAT_FUNCTION(3, 4);
// TODO: Come up with a better logging scheme for Swift.
/**
* Logs a debug message to the Xcode console and the device log. If running from AppStore, will
* not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming.
* This function is intended to be used by Swift clients that do not support variadic parameters.
* This function is similar to the one above, except it takes a `va_list` instead of the listed
* variables.
*
* @param service The service name of type `FirebaseLoggerService`.
* @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized
* three-character service identifier and a six digit integer message ID that is unique within the
* service. An example of the message code is @"I-COR000001".
* @param message The message string.
*/
extern void FIRLogDebugSwift(FIRLoggerService service, NSString *messageCode, NSString *message);
/**
* Logs a warning message to the Xcode console and the device log. If running from AppStore, will
* not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming.
* This function is intended to be used by Swift clients that do not support variadic parameters.
* The following functions accept the following parameters in order: (required) service
* name of type FirebaseLoggerService.
*
* @param service The service name of type `FirebaseLoggerService`.
* @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized
* three-character service identifier and a six digit integer message ID that is unique within the
* service. An example of the message code is @"I-COR000001".
* @param message The message string.
* (required) message code starting from "I-" which means iOS,
* followed by a capitalized three-character service identifier and a six digit integer message
* ID that is unique within the service. An example of the message code is @"I-COR000001".
* See go/firebase-log-proposal for details.
* (required) message string which can be a format string.
* (optional) A va_list
*/
extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode, NSString *message);
extern void FIRLogBasicError(NSString *category,
NSString *messageCode,
NSString *message,
va_list args_ptr);
extern void FIRLogBasicWarning(NSString *category,
NSString *messageCode,
NSString *message,
va_list args_ptr);
extern void FIRLogBasicNotice(NSString *category,
NSString *messageCode,
NSString *message,
va_list args_ptr);
extern void FIRLogBasicInfo(NSString *category,
NSString *messageCode,
NSString *message,
va_list args_ptr);
extern void FIRLogBasicDebug(NSString *category,
NSString *messageCode,
NSString *message,
va_list args_ptr);
#ifdef __cplusplus
} // extern "C"
@@ -155,35 +176,17 @@ extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode,
NS_SWIFT_NAME(FirebaseLogger)
@interface FIRLoggerWrapper : NSObject
/// Logs a given message at a given log level. This API is effectively a wrapper for the
/// `FIRLogBasic` C API.
///
/// - Parameters:
/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values).
/// - service: The service name of type `FirebaseLoggerService`.
/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized
/// three-character service identifier and a six digit integer message ID that is unique within
/// the service. An example of the message code is @"I-COR000001".
/// - message: Formatted string to be used as the log's message.
/// - args: Arguments list obtained from calling `va_start`, used when message is a format string.
+ (void)logWithLevel:(FIRLoggerLevel)level
withService:(FIRLoggerService)service
withCode:(NSString *)messageCode
withMessage:(NSString *)message
withArgs:(va_list)args;
/// Logs a given message at a given log level.
///
/// - Parameters:
/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values).
/// - service: The service name of type `FirebaseLoggerService`.
/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized
/// - category: The service name of type `FirebaseLoggerService`.
/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized
/// three-character service identifier and a six digit integer message ID that is unique within
/// the service. An example of the message code is @"I-COR000001".
/// - message: Formatted string to be used as the log's message.
/// - args: Arguments list obtained from calling `va_start`, used when message is a format string.
+ (void)logWithLevel:(FIRLoggerLevel)level
service:(FIRLoggerService)service
service:(NSString *)category
code:(NSString *)code
message:(NSString *)message
__attribute__((__swift_name__("log(level:service:code:message:)")));
@@ -191,3 +194,5 @@ NS_SWIFT_NAME(FirebaseLogger)
@end
NS_ASSUME_NONNULL_END
#endif // FIREBASECORE_FIRLOGGER_H

View File

@@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FIREBASECORE_FIREBASECOREINTERNAL_H
#define FIREBASECORE_FIREBASECOREINTERNAL_H
@import FirebaseCore;
#import "FIRAppInternal.h"
#import "FIRComponent.h"
#import "FIRComponentContainer.h"
#import "FIRComponentType.h"
#import "FIRDependency.h"
#import "FIRHeartbeatLogger.h"
#import "FIRLibrary.h"
#import "FIRLogger.h"
#import "FIROptionsInternal.h"
#endif // FIREBASECORE_FIREBASECOREINTERNAL_H

View File

@@ -16,27 +16,6 @@
#import <FirebaseCore/FIROptions.h>
/**
* Keys for the strings in the plist file.
*/
extern NSString *const kFIRAPIKey;
extern NSString *const kFIRTrackingID;
extern NSString *const kFIRGoogleAppID;
extern NSString *const kFIRClientID;
extern NSString *const kFIRGCMSenderID;
extern NSString *const kFIRAndroidClientID;
extern NSString *const kFIRDatabaseURL;
extern NSString *const kFIRStorageBucket;
extern NSString *const kFIRBundleID;
extern NSString *const kFIRProjectID;
/**
* Keys for the plist file name
*/
extern NSString *const kServiceInfoFileName;
extern NSString *const kServiceInfoFileType;
/**
* This header file exposes the initialization of FirebaseOptions to internal use.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -14,11 +14,13 @@
* limitations under the License.
*/
#import "FIRDocumentSnapshot+Internal.h"
#import <FirebaseCore/FIRTimestamp.h>
#include <utility>
#include <vector>
#import "FIRDocumentSnapshot+Internal.h"
#include "Firestore/core/src/util/warnings.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
@@ -26,7 +28,6 @@
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/API/FIRGeoPoint+Internal.h"
#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
#import "Firestore/Source/API/FIRTimestamp+Internal.h"
#import "Firestore/Source/API/FSTUserDataWriter.h"
#import "Firestore/Source/API/converters.h"

View File

@@ -15,6 +15,7 @@
*/
#import "Firestore/Source/API/FIRFieldValue+Internal.h"
#import "Firestore/Source/Public/FirebaseFirestore/FIRVectorValue.h"
NS_ASSUME_NONNULL_BEGIN
@@ -176,6 +177,10 @@ NS_ASSUME_NONNULL_BEGIN
return [[FSTNumericIncrementFieldValue alloc] initWithOperand:@(l)];
}
+ (nonnull FIRVectorValue *)vectorWithArray:(nonnull NSArray<NSNumber *> *)array {
return [[FIRVectorValue alloc] initWithArray:array];
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,152 +0,0 @@
/*
* 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 "Firestore/Source/API/FIRTimestamp+Internal.h"
NS_ASSUME_NONNULL_BEGIN
static const int kNanosPerSecond = 1000000000;
@implementation FIRTimestamp (Internal)
#pragma mark - Internal public methods
- (NSString *)ISO8601String {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSDate *secondsDate = [NSDate dateWithTimeIntervalSince1970:self.seconds];
NSString *secondsString = [formatter stringFromDate:secondsDate];
if (secondsString.length != 19) {
[NSException raise:@"Invalid ISO string" format:@"Invalid ISO string: %@", secondsString];
}
NSString *nanosString = [NSString stringWithFormat:@"%09d", self.nanoseconds];
return [NSString stringWithFormat:@"%@.%@Z", secondsString, nanosString];
}
@end
@implementation FIRTimestamp
#pragma mark - Constructors
+ (instancetype)timestampWithDate:(NSDate *)date {
double secondsDouble;
double fraction = modf(date.timeIntervalSince1970, &secondsDouble);
// GCP Timestamps always have non-negative nanos.
if (fraction < 0) {
fraction += 1.0;
secondsDouble -= 1.0;
}
int64_t seconds = (int64_t)secondsDouble;
int32_t nanos = (int32_t)(fraction * kNanosPerSecond);
return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanos];
}
+ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds {
return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanoseconds];
}
+ (instancetype)timestamp {
return [FIRTimestamp timestampWithDate:[NSDate date]];
}
- (instancetype)initWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds {
self = [super init];
if (self) {
if (nanoseconds < 0) {
[NSException raise:@"Invalid timestamp"
format:@"Timestamp nanoseconds out of range: %d", nanoseconds];
}
if (nanoseconds >= 1e9) {
[NSException raise:@"Invalid timestamp"
format:@"Timestamp nanoseconds out of range: %d", nanoseconds];
}
// Midnight at the beginning of 1/1/1 is the earliest timestamp supported.
if (seconds < -62135596800L) {
[NSException raise:@"Invalid timestamp"
format:@"Timestamp seconds out of range: %lld", seconds];
}
// This will break in the year 10,000.
if (seconds >= 253402300800L) {
[NSException raise:@"Invalid timestamp"
format:@"Timestamp seconds out of range: %lld", seconds];
}
_seconds = seconds;
_nanoseconds = nanoseconds;
}
return self;
}
#pragma mark - NSObject methods
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRTimestamp class]]) {
return NO;
}
return [self isEqualToTimestamp:(FIRTimestamp *)object];
}
- (NSUInteger)hash {
return (NSUInteger)((self.seconds >> 32) ^ self.seconds ^ self.nanoseconds);
}
- (NSString *)description {
return [NSString stringWithFormat:@"<FIRTimestamp: seconds=%lld nanoseconds=%d>", self.seconds,
self.nanoseconds];
}
/** Implements NSCopying without actually copying because timestamps are immutable. */
- (id)copyWithZone:(__unused NSZone *_Nullable)zone {
return self;
}
#pragma mark - Public methods
- (NSDate *)dateValue {
NSTimeInterval interval = (NSTimeInterval)self.seconds + ((NSTimeInterval)self.nanoseconds) / 1e9;
return [NSDate dateWithTimeIntervalSince1970:interval];
}
- (NSComparisonResult)compare:(FIRTimestamp *)other {
if (self.seconds < other.seconds) {
return NSOrderedAscending;
} else if (self.seconds > other.seconds) {
return NSOrderedDescending;
}
if (self.nanoseconds < other.nanoseconds) {
return NSOrderedAscending;
} else if (self.nanoseconds > other.nanoseconds) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
#pragma mark - Private methods
- (BOOL)isEqualToTimestamp:(FIRTimestamp *)other {
return [self compare:other] == NSOrderedSame;
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2024 Google LLC
*
* 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 <Foundation/Foundation.h>
#include "Firestore/Source/Public/FirebaseFirestore/FIRVectorValue.h"
NS_ASSUME_NONNULL_BEGIN
@implementation FIRVectorValue
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array {
if (self = [super init]) {
_array = [array valueForKey:@"doubleValue"];
}
return self;
}
- (BOOL)isEqual:(nullable id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FIRVectorValue class]]) {
return NO;
}
FIRVectorValue *otherVector = ((FIRVectorValue *)object);
return [self.array isEqualToArray:otherVector.array];
}
@end
NS_ASSUME_NONNULL_END

View File

@@ -22,14 +22,13 @@
#include <string>
#include <utility>
#import "FirebaseAuth/Interop/FIRAuthInterop.h"
#import "FirebaseAuth/Interop/Public/FirebaseAuthInterop/FIRAuthInterop.h"
#import "FirebaseCore/Extension/FIRAppInternal.h"
#import "FirebaseCore/Extension/FIRComponent.h"
#import "FirebaseCore/Extension/FIRComponentContainer.h"
#import "FirebaseCore/Extension/FIRComponentType.h"
#import "FirebaseCore/Extension/FIRDependency.h"
#import "FirebaseCore/Extension/FIRLibrary.h"
#import "FirebaseCore/Extension/FIROptionsInternal.h"
#import "FirebaseCore/Sources/FIROptionsInternal.h"
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#include "Firestore/core/include/firebase/firestore/firestore_version.h"
@@ -160,12 +159,9 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Interoperability
+ (NSArray<FIRComponent *> *)componentsToRegister {
FIRDependency *auth = [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop)
isRequired:NO];
FIRComponent *firestoreProvider = [FIRComponent
componentWithProtocol:@protocol(FSTFirestoreMultiDBProvider)
instantiationTiming:FIRInstantiationTimingLazy
dependencies:@[ auth ]
creationBlock:^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {
FSTFirestoreComponent *multiDBComponent =
[[FSTFirestoreComponent alloc] initWithApp:container.app];

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
#import "Firestore/Source/API/FSTUserDataReader.h"
#import <FirebaseCore/FIRTimestamp.h>
#include <memory>
#include <set>
@@ -22,8 +22,10 @@
#include <utility>
#include <vector>
#import "Firestore/Source/API/FSTUserDataReader.h"
#import "FIRGeoPoint.h"
#import "FIRTimestamp.h"
#import "FIRVectorValue.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
#import "Firestore/Source/API/FIRFieldPath+Internal.h"
@@ -340,6 +342,42 @@ NS_ASSUME_NONNULL_BEGIN
return std::move(result);
}
- (Message<google_firestore_v1_Value>)parseVectorValue:(FIRVectorValue *)vectorValue
context:(ParseContext &&)context {
__block Message<google_firestore_v1_Value> result;
result->which_value_type = google_firestore_v1_Value_map_value_tag;
result->map_value = {};
result->map_value.fields_count = 2;
result->map_value.fields = nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(2);
result->map_value.fields[0].key = nanopb::CopyBytesArray(model::kTypeValueFieldKey);
result->map_value.fields[0].value = *[self encodeStringValue:MakeString(@"__vector__")].release();
NSArray<NSNumber *> *vectorArray = vectorValue.array;
__block Message<google_firestore_v1_Value> arrayMessage;
arrayMessage->which_value_type = google_firestore_v1_Value_array_value_tag;
arrayMessage->array_value.values_count = CheckedSize([vectorArray count]);
arrayMessage->array_value.values =
nanopb::MakeArray<google_firestore_v1_Value>(arrayMessage->array_value.values_count);
[vectorArray enumerateObjectsUsingBlock:^(id entry, NSUInteger idx, BOOL *) {
if (![entry isKindOfClass:[NSNumber class]]) {
ThrowInvalidArgument("VectorValues must only contain numeric values.",
context.FieldDescription());
}
// Vector values must always use Double encoding
arrayMessage->array_value.values[idx] = *[self encodeDouble:[entry doubleValue]].release();
}];
result->map_value.fields[1].key = nanopb::CopyBytesArray(model::kVectorValueFieldKey);
result->map_value.fields[1].value = *arrayMessage.release();
return std::move(result);
}
- (Message<google_firestore_v1_Value>)parseArray:(NSArray<id> *)array
context:(ParseContext &&)context {
__block Message<google_firestore_v1_Value> result;
@@ -528,7 +566,9 @@ NS_ASSUME_NONNULL_BEGIN
_databaseID.database_id(), context.FieldDescription());
}
return [self encodeReference:_databaseID key:reference.key];
} else if ([input isKindOfClass:[FIRVectorValue class]]) {
FIRVectorValue *vector = input;
return [self parseVectorValue:vector context:std::move(context)];
} else {
ThrowInvalidArgument("Unsupported type: %s%s", NSStringFromClass([input class]),
context.FieldDescription());

View File

@@ -21,6 +21,7 @@
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
#include "Firestore/Source/API/FIRDocumentReference+Internal.h"
#include "Firestore/Source/API/FIRFieldValue+Internal.h"
#include "Firestore/Source/API/converters.h"
#include "Firestore/core/include/firebase/firestore/geo_point.h"
#include "Firestore/core/include/firebase/firestore/timestamp.h"
@@ -105,6 +106,8 @@ NS_ASSUME_NONNULL_BEGIN
case TypeOrder::kGeoPoint:
return MakeFIRGeoPoint(
GeoPoint(value.geo_point_value.latitude, value.geo_point_value.longitude));
case TypeOrder::kVector:
return [self convertedVector:value.map_value];
case TypeOrder::kMaxValue:
// It is not possible for users to construct a kMaxValue manually.
break;
@@ -123,6 +126,18 @@ NS_ASSUME_NONNULL_BEGIN
return result;
}
- (FIRVectorValue *)convertedVector:(const google_firestore_v1_MapValue &)mapValue {
for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
absl::string_view key = MakeStringView(mapValue.fields[i].key);
const google_firestore_v1_Value &value = mapValue.fields[i].value;
if ((0 == key.compare(absl::string_view("value"))) &&
value.which_value_type == google_firestore_v1_Value_array_value_tag) {
return [FIRFieldValue vectorWithArray:[self convertedArray:value.array_value]];
}
}
return [FIRFieldValue vectorWithArray:@[]];
}
- (NSArray<id> *)convertedArray:(const google_firestore_v1_ArrayValue &)arrayValue {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayValue.values_count];
for (pb_size_t i = 0; i < arrayValue.values_count; ++i) {

View File

@@ -14,12 +14,13 @@
* limitations under the License.
*/
#include "Firestore/Source/API/converters.h"
#import <FirebaseCore/FIRTimestamp.h>
#include <utility>
#include "Firestore/Source/API/converters.h"
#import "FIRGeoPoint.h"
#import "FIRTimestamp.h"
#include "Firestore/Source/API/FIRDocumentReference+Internal.h"
#include "Firestore/core/include/firebase/firestore/geo_point.h"

View File

@@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Represents an aggregation that can be performed by Firestore.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(AggregateField)
@interface FIRAggregateField : NSObject

View File

@@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* A query that calculates aggregations over an underlying query.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(AggregateQuery)
@interface FIRAggregateQuery : NSObject

View File

@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* The results of executing an `AggregateQuery`.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(AggregateQuerySnapshot)
@interface FIRAggregateQuerySnapshot : NSObject

View File

@@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
* A `CollectionReference` object can be used for adding documents, getting document references,
* and querying for documents (using the methods inherited from `Query`).
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(CollectionReference)
@interface FIRCollectionReference : FIRQuery

View File

@@ -43,6 +43,7 @@ typedef NS_ENUM(NSInteger, FIRDocumentChangeType)
* A `DocumentChange` represents a change to the documents matching a query. It contains the
* document affected and the type of change that occurred (added, modified, or removed).
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(DocumentChange)
@interface FIRDocumentChange : NSObject

View File

@@ -39,6 +39,7 @@ typedef void (^FIRDocumentSnapshotBlock)(FIRDocumentSnapshot *_Nullable snapshot
* may or may not exist. A `DocumentReference` can also be used to create a `CollectionReference` to
* a subcollection.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(DocumentReference)
@interface FIRDocumentReference : NSObject

View File

@@ -55,6 +55,7 @@ typedef NS_ENUM(NSInteger, FIRServerTimestampBehavior) {
* For a `DocumentSnapshot` that points to a non-existing document, any data access will return
* `nil`. You can use the `exists` property to explicitly verify a documents existence.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(DocumentSnapshot)
@interface FIRDocumentSnapshot : NSObject

View File

@@ -23,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
* (referring to a top level field in the document), or a list of field names (referring to a nested
* field in the document).
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(FieldPath)
@interface FIRFieldPath : NSObject <NSCopying>

View File

@@ -17,10 +17,12 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class FIRVectorValue;
/**
* Sentinel values that can be used when writing document fields with `setData()` or `updateData()`.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(FieldValue)
@interface FIRFieldValue : NSObject
@@ -90,6 +92,14 @@ NS_SWIFT_NAME(FieldValue)
*/
+ (instancetype)fieldValueForIntegerIncrement:(int64_t)l NS_SWIFT_NAME(increment(_:));
/**
* Creates a new `VectorValue` constructed with a copy of the given array of NSNumbers.
*
* @param array Create a `VectorValue` instance with a copy of this array of NSNumbers.
* @return A new `VectorValue` constructed with a copy of the given array of NSNumbers.
*/
+ (FIRVectorValue *)vectorWithArray:(NSArray<NSNumber *> *)array NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END

View File

@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
* A Filter represents a restriction on one or more field values and can be used to refine
* the results of a Query.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(Filter)
@interface FIRFilter : NSObject

View File

@@ -25,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
* Latitude values are in the range of [-90, 90].
* Longitude values are in the range of [-180, 180].
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(GeoPoint)
@interface FIRGeoPoint : NSObject <NSCopying>

View File

@@ -36,6 +36,7 @@ typedef NS_ENUM(NSInteger, FIRLoadBundleTaskState) {
/** Represents a progress update or a final state from loading bundles. */
NS_SWIFT_NAME(LoadBundleTaskProgress)
NS_SWIFT_SENDABLE
@interface FIRLoadBundleTaskProgress : NSObject
/** How many documents have been loaded. */

View File

@@ -44,14 +44,14 @@ NS_SWIFT_NAME(PersistentCacheSettings)
/**
* Creates `PersistentCacheSettings` with default cache size: 100MB.
*
* The cache size is not a hard limit, but a target for the SDK's gabarge collector to work towards.
* The cache size is not a hard limit, but a target for the SDK's garbage collector to work towards.
*/
- (instancetype)init;
/**
* Creates `PersistentCacheSettings` with a custom cache size in bytes.
*
* The cache size is not a hard limit, but a target for the SDK's gabarge collector to work towards.
* The cache size is not a hard limit, but a target for the SDK's garbage collector to work towards.
*/
- (instancetype)initWithSizeBytes:(NSNumber *)size;
@@ -132,7 +132,7 @@ NS_SWIFT_NAME(MemoryCacheSettings)
/**
* Creates an instance of `MemoryCacheSettings` with given `MemoryGarbageCollectorSettings` to
* custom the gabarge collector.
* custom the garbage collector.
*/
- (instancetype)initWithGarbageCollectorSettings:
(id<FIRMemoryGarbageCollectorSettings, NSObject>)settings;

View File

@@ -41,6 +41,7 @@ typedef void (^FIRQuerySnapshotBlock)(FIRQuerySnapshot *_Nullable snapshot,
* A `Query` refers to a query which you can read or listen to. You can also construct
* refined `Query` objects by adding filters and ordering.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(Query)
@interface FIRQuery : NSObject
/** :nodoc: */

View File

@@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
* using the `documents` property and its size can be inspected with `isEmpty` and
* `count`.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(QuerySnapshot)
@interface FIRQuerySnapshot : NSObject

View File

@@ -44,6 +44,7 @@ typedef NS_ENUM(NSUInteger, FIRListenSource) {
* of this class control settings like whether metadata-only changes trigger events and the
* preferred data source.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(SnapshotListenOptions)
@interface FIRSnapshotListenOptions : NSObject
@@ -61,7 +62,7 @@ NS_SWIFT_NAME(SnapshotListenOptions)
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Creates and returns a new `SnapshotListenOptions` object with with all properties of the current
* Creates and returns a new `SnapshotListenOptions` object with all properties of the current
* `SnapshotListenOptions` object plus the new property specifying whether metadata-only changes
* should trigger snapshot events
*
@@ -70,7 +71,7 @@ NS_SWIFT_NAME(SnapshotListenOptions)
- (FIRSnapshotListenOptions *)optionsWithIncludeMetadataChanges:(BOOL)includeMetadataChanges;
/**
* Creates and returns a new `SnapshotListenOptions` object with with all properties of the current
* Creates and returns a new `SnapshotListenOptions` object with all properties of the current
* `SnapshotListenOptions` object plus the new property specifying the source that the snapshot
* listener listens to.
*

View File

@@ -19,6 +19,7 @@
NS_ASSUME_NONNULL_BEGIN
/** Metadata about a snapshot, describing the state of the snapshot. */
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(SnapshotMetadata)
@interface FIRSnapshotMetadata : NSObject

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2018 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* A Timestamp represents a point in time independent of any time zone or calendar, represented as
* seconds and fractions of seconds at nanosecond resolution in UTC Epoch time. It is encoded using
* the Proleptic Gregorian Calendar which extends the Gregorian calendar backwards to year one. It
* is encoded assuming all minutes are 60 seconds long, i.e. leap seconds are "smeared" so that no
* leap second table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59.999999999Z. By restricting to that range, we ensure that we can convert to
* and from RFC 3339 date strings.
*
* @see https://github.com/google/protobuf/blob/main/src/google/protobuf/timestamp.proto for the
* reference timestamp definition.
*/
NS_SWIFT_NAME(Timestamp)
@interface FIRTimestamp : NSObject <NSCopying>
/** :nodoc: */
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a new timestamp.
*
* @param seconds the number of seconds since epoch.
* @param nanoseconds the number of nanoseconds after the seconds.
*/
- (instancetype)initWithSeconds:(int64_t)seconds
nanoseconds:(int32_t)nanoseconds NS_DESIGNATED_INITIALIZER;
/**
* Creates a new timestamp.
*
* @param seconds the number of seconds since epoch.
* @param nanoseconds the number of nanoseconds after the seconds.
*/
+ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds;
/** Creates a new timestamp from the given date. */
+ (instancetype)timestampWithDate:(NSDate *)date;
/** Creates a new timestamp with the current date / time. */
+ (instancetype)timestamp;
/** Returns a new `Date` corresponding to this timestamp. This may lose precision. */
- (NSDate *)dateValue;
/**
* Returns the result of comparing the receiver with another timestamp.
* @param other the other timestamp to compare.
* @return `orderedAscending` if `other` is chronologically following self,
* `orderedDescending` if `other` is chronologically preceding self,
* `orderedSame` otherwise.
*/
- (NSComparisonResult)compare:(FIRTimestamp *)other;
/**
* Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
* Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.
*/
@property(nonatomic, assign, readonly) int64_t seconds;
/**
* Non-negative fractions of a second at nanosecond resolution. Negative second values with
* fractions must still have non-negative nanos values that count forward in time.
* Must be from 0 to 999,999,999 inclusive.
*/
@property(nonatomic, assign, readonly) int32_t nanoseconds;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2024 Google LLC
*
* 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a vector type in Firestore documents.
*/
NS_SWIFT_SENDABLE
NS_SWIFT_NAME(VectorValue)
@interface FIRVectorValue : NSObject
/** Returns a copy of the raw number array that represents the vector. */
@property(atomic, readonly) NSArray<NSNumber *> *array NS_REFINED_FOR_SWIFT;
/** :nodoc: */
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a `VectorValue` constructed with a copy of the given array of NSNumbrers.
* @param array An array of NSNumbers that represents a vector.
*/
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END

View File

@@ -36,7 +36,6 @@
#import "FIRQuerySnapshot.h"
#import "FIRSnapshotListenOptions.h"
#import "FIRSnapshotMetadata.h"
#import "FIRTimestamp.h"
#import "FIRTransaction.h"
#import "FIRTransactionOptions.h"
#import "FIRWriteBatch.h"

View File

@@ -19,13 +19,11 @@
#include <cstdint>
#include <ctime>
#include <chrono>
#include <iosfwd>
#include <string>
#if !defined(_STLPORT_VERSION)
#include <chrono> // NOLINT(build/c++11)
#endif // !defined(_STLPORT_VERSION)
namespace firebase {
/**
@@ -117,7 +115,6 @@ class Timestamp {
*/
static Timestamp FromTimeT(time_t seconds_since_unix_epoch);
#if !defined(_STLPORT_VERSION)
/**
* Converts `std::chrono::time_point` to a `Timestamp`.
*
@@ -145,7 +142,6 @@ class Timestamp {
template <typename Clock = std::chrono::system_clock,
typename Duration = std::chrono::microseconds>
std::chrono::time_point<Clock, Duration> ToTimePoint() const;
#endif // !defined(_STLPORT_VERSION)
/**
* Returns a string representation of this `Timestamp` for logging/debugging
@@ -205,8 +201,6 @@ inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) {
return !(lhs != rhs);
}
#if !defined(_STLPORT_VERSION)
// Make sure the header compiles even when included after `<windows.h>` without
// `NOMINMAX` defined. `push/pop_macro` pragmas are supported by Visual Studio
// as well as Clang and GCC.
@@ -239,8 +233,6 @@ std::chrono::time_point<Clock, Duration> Timestamp::ToTimePoint() const {
#pragma pop_macro("max")
#pragma pop_macro("min")
#endif // !defined(_STLPORT_VERSION)
} // namespace firebase
#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TIMESTAMP_H_

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/api/document_reference.h"
#include <future> // NOLINT(build/c++11)
#include <future>
#include <memory>
#include "Firestore/core/src/api/collection_reference.h"

View File

@@ -18,7 +18,7 @@
#define FIRESTORE_CORE_SRC_API_FIRESTORE_H_
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include "Firestore/core/src/api/api_fwd.h"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2024 Google
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/api/load_bundle_task.h"
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <utility>
#include "Firestore/core/src/util/autoid.h"

View File

@@ -19,7 +19,7 @@
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <utility>
#include <vector>

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/api/query_core.h"
#include <future> // NOLINT(build/c++11)
#include <future>
#include <memory>
#include <utility>
#include <vector>

View File

@@ -69,15 +69,15 @@ std::unique_ptr<LocalCacheSettings> Settings::CopyCacheSettings(
UNREACHABLE();
}
std::unique_ptr<MemoryGargabeCollectorSettings>
std::unique_ptr<MemoryGarbageCollectorSettings>
MemoryCacheSettings::CopyMemoryGcSettings(
const MemoryGargabeCollectorSettings& settings) {
const MemoryGarbageCollectorSettings& settings) {
if (settings.kind() ==
MemoryGargabeCollectorSettings::MemoryGcKind::kEagerGc) {
MemoryGarbageCollectorSettings::MemoryGcKind::kEagerGc) {
return absl::make_unique<MemoryEagerGcSettings>(
static_cast<const MemoryEagerGcSettings&>(settings));
} else if (settings.kind() ==
MemoryGargabeCollectorSettings::MemoryGcKind::kLruGc) {
MemoryGarbageCollectorSettings::MemoryGcKind::kLruGc) {
return absl::make_unique<MemoryLruGcSettings>(
static_cast<const MemoryLruGcSettings&>(settings));
}
@@ -107,7 +107,7 @@ MemoryLruGcSettings MemoryLruGcSettings::WithSizeBytes(int64_t size) const {
}
MemoryCacheSettings MemoryCacheSettings::WithMemoryGarbageCollectorSettings(
const MemoryGargabeCollectorSettings& settings) {
const MemoryGarbageCollectorSettings& settings) {
MemoryCacheSettings new_settings(*this);
new_settings.settings_ = CopyMemoryGcSettings(settings);
return new_settings;
@@ -157,18 +157,18 @@ bool operator==(const LocalCacheSettings& lhs, const LocalCacheSettings& rhs) {
UNREACHABLE();
}
bool operator==(const MemoryGargabeCollectorSettings& lhs,
const MemoryGargabeCollectorSettings& rhs) {
bool operator==(const MemoryGarbageCollectorSettings& lhs,
const MemoryGarbageCollectorSettings& rhs) {
if (lhs.kind() != rhs.kind()) {
return false;
}
if (lhs.kind() == MemoryGargabeCollectorSettings::MemoryGcKind::kEagerGc) {
if (lhs.kind() == MemoryGarbageCollectorSettings::MemoryGcKind::kEagerGc) {
return static_cast<const MemoryEagerGcSettings&>(lhs) ==
static_cast<const MemoryEagerGcSettings&>(rhs);
}
if (lhs.kind() == MemoryGargabeCollectorSettings::MemoryGcKind::kLruGc) {
if (lhs.kind() == MemoryGarbageCollectorSettings::MemoryGcKind::kLruGc) {
return static_cast<const MemoryLruGcSettings&>(lhs) ==
static_cast<const MemoryLruGcSettings&>(rhs);
}
@@ -268,7 +268,7 @@ int64_t Settings::cache_size_bytes() const {
auto* memory_cache_settings =
static_cast<MemoryCacheSettings*>(cache_settings_.get());
if (memory_cache_settings->gc_settings().kind() ==
MemoryGargabeCollectorSettings::MemoryGcKind::kLruGc) {
MemoryGarbageCollectorSettings::MemoryGcKind::kLruGc) {
return static_cast<const MemoryLruGcSettings&>(
memory_cache_settings->gc_settings())
.size_bytes();
@@ -289,14 +289,14 @@ bool Settings::gc_enabled() const {
auto* memory_cache_settings =
static_cast<MemoryCacheSettings*>(cache_settings_.get());
return memory_cache_settings->gc_settings().kind() ==
MemoryGargabeCollectorSettings::MemoryGcKind::kLruGc &&
MemoryGarbageCollectorSettings::MemoryGcKind::kLruGc &&
static_cast<const MemoryLruGcSettings&>(
memory_cache_settings->gc_settings())
.size_bytes() != CacheSizeUnlimited;
}
}
return persistence_enabled_ && cache_size_bytes_ != CacheSizeUnlimited;
return cache_size_bytes_ != CacheSizeUnlimited;
}
const LocalCacheSettings* Settings::local_cache_settings() const {

View File

@@ -97,7 +97,7 @@ class LocalCacheSettings {
friend class Settings;
public:
enum class Kind { kMemory, kPersistent };
enum class Kind { kMemory = 1, kPersistent };
virtual ~LocalCacheSettings() = default;
friend bool operator==(const LocalCacheSettings& lhs,
const LocalCacheSettings& rhs);
@@ -133,12 +133,13 @@ class PersistentCacheSettings : public LocalCacheSettings {
int64_t size_bytes_;
};
class MemoryGargabeCollectorSettings {
class MemoryGarbageCollectorSettings {
public:
enum class MemoryGcKind { kEagerGc, kLruGc };
virtual ~MemoryGargabeCollectorSettings() = default;
friend bool operator==(const MemoryGargabeCollectorSettings& lhs,
const MemoryGargabeCollectorSettings& rhs);
enum class MemoryGcKind { kEagerGc = 1, kLruGc };
virtual ~MemoryGarbageCollectorSettings() = default;
friend bool operator==(const MemoryGarbageCollectorSettings& lhs,
const MemoryGarbageCollectorSettings& rhs);
virtual size_t Hash() const = 0;
MemoryGcKind kind() const {
@@ -146,25 +147,25 @@ class MemoryGargabeCollectorSettings {
}
protected:
explicit MemoryGargabeCollectorSettings(MemoryGcKind kind) : kind_(kind) {
explicit MemoryGarbageCollectorSettings(MemoryGcKind kind) : kind_(kind) {
}
MemoryGcKind kind_;
};
class MemoryEagerGcSettings : public MemoryGargabeCollectorSettings {
class MemoryEagerGcSettings : public MemoryGarbageCollectorSettings {
public:
MemoryEagerGcSettings()
: MemoryGargabeCollectorSettings(
MemoryGargabeCollectorSettings::MemoryGcKind::kEagerGc) {
: MemoryGarbageCollectorSettings(
MemoryGarbageCollectorSettings::MemoryGcKind::kEagerGc) {
}
size_t Hash() const override;
};
class MemoryLruGcSettings : public MemoryGargabeCollectorSettings {
class MemoryLruGcSettings : public MemoryGarbageCollectorSettings {
public:
MemoryLruGcSettings()
: MemoryGargabeCollectorSettings(
MemoryGargabeCollectorSettings::MemoryGcKind::kLruGc),
: MemoryGarbageCollectorSettings(
MemoryGarbageCollectorSettings::MemoryGcKind::kLruGc),
size_bytes_(Settings::DefaultCacheSizeBytes) {
}
@@ -185,7 +186,7 @@ class MemoryCacheSettings : public LocalCacheSettings {
public:
MemoryCacheSettings()
: LocalCacheSettings(LocalCacheSettings::Kind::kMemory),
settings_(absl::make_unique<MemoryEagerGcSettings>()) {
settings_(absl::make_unique<MemoryLruGcSettings>()) {
}
MemoryCacheSettings(const MemoryCacheSettings& other);
MemoryCacheSettings& operator=(const MemoryCacheSettings& other);
@@ -193,17 +194,17 @@ class MemoryCacheSettings : public LocalCacheSettings {
size_t Hash() const override;
MemoryCacheSettings WithMemoryGarbageCollectorSettings(
const MemoryGargabeCollectorSettings& settings);
const MemoryGarbageCollectorSettings& settings);
const MemoryGargabeCollectorSettings& gc_settings() const {
const MemoryGarbageCollectorSettings& gc_settings() const {
return *settings_;
}
private:
static std::unique_ptr<MemoryGargabeCollectorSettings> CopyMemoryGcSettings(
const MemoryGargabeCollectorSettings& settings);
static std::unique_ptr<MemoryGarbageCollectorSettings> CopyMemoryGcSettings(
const MemoryGarbageCollectorSettings& settings);
std::unique_ptr<MemoryGargabeCollectorSettings> settings_;
std::unique_ptr<MemoryGarbageCollectorSettings> settings_;
};
bool operator!=(const Settings& lhs, const Settings& rhs);

View File

@@ -17,6 +17,7 @@
#include "Firestore/core/src/core/composite_filter.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "Firestore/core/src/core/field_filter.h"
@@ -141,16 +142,14 @@ const FieldFilter* CompositeFilter::Rep::FindFirstMatchingFilter(
return nullptr;
}
const std::vector<FieldFilter>& CompositeFilter::Rep::GetFlattenedFilters()
const {
return memoized_flattened_filters_->memoize([&]() {
std::vector<FieldFilter> flattened_filters;
for (const auto& filter : filters())
std::copy(filter.GetFlattenedFilters().begin(),
filter.GetFlattenedFilters().end(),
std::back_inserter(flattened_filters));
return flattened_filters;
});
std::shared_ptr<std::vector<FieldFilter>>
CompositeFilter::Rep::CalculateFlattenedFilters() const {
auto flattened_filters = std::make_shared<std::vector<FieldFilter>>();
for (const auto& filter : filters())
std::copy(filter.GetFlattenedFilters().begin(),
filter.GetFlattenedFilters().end(),
std::back_inserter(*flattened_filters));
return flattened_filters;
}
} // namespace core

View File

@@ -138,7 +138,8 @@ class CompositeFilter : public Filter {
return filters_.empty();
}
const std::vector<FieldFilter>& GetFlattenedFilters() const override;
std::shared_ptr<std::vector<FieldFilter>> CalculateFlattenedFilters()
const override;
std::vector<Filter> GetFilters() const override {
return filters();

View File

@@ -18,7 +18,7 @@
#define FIRESTORE_CORE_SRC_CORE_EVENT_LISTENER_H_
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <utility>
#include "Firestore/core/src/util/executor.h"

View File

@@ -16,6 +16,7 @@
#include "Firestore/core/src/core/field_filter.h"
#include <memory>
#include <utility>
#include "Firestore/core/src/core/array_contains_any_filter.h"
@@ -122,12 +123,12 @@ FieldFilter::FieldFilter(std::shared_ptr<const Filter::Rep> rep)
: Filter(std::move(rep)) {
}
const std::vector<FieldFilter>& FieldFilter::Rep::GetFlattenedFilters() const {
std::shared_ptr<std::vector<FieldFilter>>
FieldFilter::Rep::CalculateFlattenedFilters() const {
// This is already a field filter, so we return a vector of size one.
return memoized_flattened_filters_->memoize([&]() {
return std::vector<FieldFilter>{
FieldFilter(std::make_shared<const Rep>(*this))};
});
auto filters = std::make_shared<std::vector<FieldFilter>>();
filters->push_back(FieldFilter(std::make_shared<const Rep>(*this)));
return filters;
}
std::vector<Filter> FieldFilter::Rep::GetFilters() const {
@@ -156,7 +157,8 @@ bool FieldFilter::Rep::Matches(const model::Document& doc) const {
// Types do not have to match in NotEqual filters.
if (op_ == Operator::NotEqual) {
return MatchesComparison(Compare(lhs, *value_rhs_));
return lhs.which_value_type != google_firestore_v1_Value_null_value_tag &&
MatchesComparison(Compare(lhs, *value_rhs_));
}
// Only compare types with matching backend order (such as double and int).

View File

@@ -117,8 +117,6 @@ class FieldFilter : public Filter {
return false;
}
const std::vector<FieldFilter>& GetFlattenedFilters() const override;
std::vector<Filter> GetFilters() const override;
protected:
@@ -140,6 +138,9 @@ class FieldFilter : public Filter {
bool MatchesComparison(util::ComparisonResult comparison) const;
std::shared_ptr<std::vector<FieldFilter>> CalculateFlattenedFilters()
const override;
private:
friend class FieldFilter;

View File

@@ -35,12 +35,6 @@ std::ostream& operator<<(std::ostream& os, const Filter& filter) {
return os << filter.ToString();
}
Filter::Rep::Rep()
: memoized_flattened_filters_(
std::make_shared<
util::ThreadSafeMemoizer<std::vector<FieldFilter>>>()) {
}
} // namespace core
} // namespace firestore
} // namespace firebase

View File

@@ -17,6 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_CORE_FILTER_H_
#define FIRESTORE_CORE_SRC_CORE_FILTER_H_
#include <functional>
#include <iosfwd>
#include <memory>
#include <string>
@@ -114,7 +115,7 @@ class Filter {
protected:
class Rep {
public:
Rep();
Rep() = default;
virtual ~Rep() = default;
@@ -147,20 +148,23 @@ class Filter {
virtual bool IsEmpty() const = 0;
virtual const std::vector<FieldFilter>& GetFlattenedFilters() const = 0;
virtual const std::vector<FieldFilter>& GetFlattenedFilters() const {
const auto func = std::bind(&Rep::CalculateFlattenedFilters, this);
return memoized_flattened_filters_.value(func);
}
virtual std::vector<Filter> GetFilters() const = 0;
protected:
virtual std::shared_ptr<std::vector<FieldFilter>>
CalculateFlattenedFilters() const = 0;
private:
/**
* Memoized list of all field filters that can be found by
* traversing the tree of filters contained in this composite filter.
*
* Use a `std::shared_ptr<ThreadSafeMemoizer>` rather than using
* `ThreadSafeMemoizer` directly so that this class is copyable
* (`ThreadSafeMemoizer` is not copyable because of its `std::once_flag`
* member variable, which is not copyable).
*/
mutable std::shared_ptr<util::ThreadSafeMemoizer<std::vector<FieldFilter>>>
mutable util::ThreadSafeMemoizer<const std::vector<FieldFilter>>
memoized_flattened_filters_;
};

View File

@@ -17,7 +17,7 @@
#include "Firestore/core/src/core/firestore_client.h"
#include <functional>
#include <future> // NOLINT(build/c++11)
#include <future>
#include <memory>
#include <string>
#include <utility>

View File

@@ -62,7 +62,10 @@ bool NotInFilter::Rep::Matches(const Document& doc) const {
return false;
}
absl::optional<google_firestore_v1_Value> maybe_lhs = doc->field(field());
return maybe_lhs && !Contains(array_value, *maybe_lhs);
return maybe_lhs &&
maybe_lhs->which_value_type !=
google_firestore_v1_Value_null_value_tag &&
!Contains(array_value, *maybe_lhs);
}
} // namespace core

View File

@@ -17,6 +17,7 @@
#include "Firestore/core/src/core/query.h"
#include <algorithm>
#include <memory>
#include <ostream>
#include "Firestore/core/src/core/bound.h"
@@ -91,44 +92,42 @@ absl::optional<Operator> Query::FindOpInsideFilters(
return absl::nullopt;
}
const std::vector<OrderBy>& Query::normalized_order_bys() const {
return memoized_normalized_order_bys_->memoize([&]() {
// Any explicit order by fields should be added as is.
std::vector<OrderBy> result = explicit_order_bys_;
std::set<FieldPath> fieldsNormalized;
for (const OrderBy& order_by : explicit_order_bys_) {
fieldsNormalized.insert(order_by.field());
std::shared_ptr<const std::vector<OrderBy>> Query::CalculateNormalizedOrderBys()
const {
// Any explicit order by fields should be added as is.
auto result = std::make_shared<std::vector<OrderBy>>(explicit_order_bys_);
std::set<FieldPath> fieldsNormalized;
for (const OrderBy& order_by : explicit_order_bys_) {
fieldsNormalized.insert(order_by.field());
}
// The order of the implicit ordering always matches the last explicit order
// by.
Direction last_direction = explicit_order_bys_.empty()
? Direction::Ascending
: explicit_order_bys_.back().direction();
// Any inequality fields not explicitly ordered should be implicitly ordered
// in a lexicographical order. When there are multiple inequality filters on
// the same field, the field should be added only once. Note:
// `std::set<model::FieldPath>` sorts the key field before other fields.
// However, we want the key field to be sorted last.
const std::set<model::FieldPath> inequality_fields = InequalityFilterFields();
for (const model::FieldPath& field : inequality_fields) {
if (fieldsNormalized.find(field) == fieldsNormalized.end() &&
!field.IsKeyFieldPath()) {
result->push_back(OrderBy(field, last_direction));
}
}
// The order of the implicit ordering always matches the last explicit order
// by.
Direction last_direction = explicit_order_bys_.empty()
? Direction::Ascending
: explicit_order_bys_.back().direction();
// Add the document key field to the last if it is not explicitly ordered.
if (fieldsNormalized.find(FieldPath::KeyFieldPath()) ==
fieldsNormalized.end()) {
result->push_back(OrderBy(FieldPath::KeyFieldPath(), last_direction));
}
// Any inequality fields not explicitly ordered should be implicitly ordered
// in a lexicographical order. When there are multiple inequality filters on
// the same field, the field should be added only once. Note:
// `std::set<model::FieldPath>` sorts the key field before other fields.
// However, we want the key field to be sorted last.
const std::set<model::FieldPath> inequality_fields =
InequalityFilterFields();
for (const model::FieldPath& field : inequality_fields) {
if (fieldsNormalized.find(field) == fieldsNormalized.end() &&
!field.IsKeyFieldPath()) {
result.push_back(OrderBy(field, last_direction));
}
}
// Add the document key field to the last if it is not explicitly ordered.
if (fieldsNormalized.find(FieldPath::KeyFieldPath()) ==
fieldsNormalized.end()) {
result.push_back(OrderBy(FieldPath::KeyFieldPath(), last_direction));
}
return result;
});
return result;
}
LimitType Query::limit_type() const {
@@ -296,14 +295,12 @@ std::string Query::ToString() const {
return absl::StrCat("Query(canonical_id=", CanonicalId(), ")");
}
const Target& Query::ToTarget() const& {
return memoized_target_->memoize(
[&]() { return ToTarget(normalized_order_bys()); });
std::shared_ptr<Target> Query::CalculateTarget() const {
return std::make_shared<Target>(ToTarget(normalized_order_bys()));
}
const Target& Query::ToAggregateTarget() const& {
return memoized_aggregate_target_->memoize(
[&]() { return ToTarget(explicit_order_bys_); });
std::shared_ptr<Target> Query::CalculateAggregateTarget() const {
return std::make_shared<Target>(ToTarget(explicit_order_bys_));
}
Target Query::ToTarget(const std::vector<OrderBy>& order_bys) const {

View File

@@ -17,6 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_CORE_QUERY_H_
#define FIRESTORE_CORE_SRC_CORE_QUERY_H_
#include <functional>
#include <iosfwd>
#include <limits>
#include <memory>
@@ -148,7 +149,10 @@ class Query {
* This might include additional sort orders added implicitly to match the
* backend behavior.
*/
const std::vector<OrderBy>& normalized_order_bys() const;
const std::vector<OrderBy>& normalized_order_bys() const {
const auto func = std::bind(&Query::CalculateNormalizedOrderBys, this);
return memoized_normalized_order_bys_.value(func);
}
bool has_limit() const {
return limit_ != Target::kNoLimit;
@@ -246,7 +250,10 @@ class Query {
* Returns a `Target` instance this query will be mapped to in backend
* and local store.
*/
const Target& ToTarget() const&;
const Target& ToTarget() const& {
const auto func = std::bind(&Query::CalculateTarget, this);
return memoized_target_.value(func);
}
/**
* Returns a `Target` instance this query will be mapped to in backend
@@ -254,7 +261,10 @@ class Query {
* for non-aggregate queries, aggregate query targets do not contain
* normalized order-bys, they only contain explicit order-bys.
*/
const Target& ToAggregateTarget() const&;
const Target& ToAggregateTarget() const& {
const auto func = std::bind(&Query::CalculateAggregateTarget, this);
return memoized_aggregate_target_.value(func);
}
friend std::ostream& operator<<(std::ostream& os, const Query& query);
@@ -289,26 +299,21 @@ class Query {
Target ToTarget(const std::vector<OrderBy>& order_bys) const;
// For properties below, use a `std::shared_ptr<ThreadSafeMemoizer>` rather
// than using `ThreadSafeMemoizer` directly so that this class is copyable
// (`ThreadSafeMemoizer` is not copyable because of its `std::once_flag`
// member variable, which is not copyable).
// The memoized list of sort orders.
mutable std::shared_ptr<util::ThreadSafeMemoizer<std::vector<OrderBy>>>
memoized_normalized_order_bys_{
std::make_shared<util::ThreadSafeMemoizer<std::vector<OrderBy>>>()};
std::shared_ptr<const std::vector<OrderBy>> CalculateNormalizedOrderBys()
const;
mutable util::ThreadSafeMemoizer<const std::vector<OrderBy>>
memoized_normalized_order_bys_;
// The corresponding Target of this Query instance.
mutable std::shared_ptr<util::ThreadSafeMemoizer<Target>> memoized_target_{
std::make_shared<util::ThreadSafeMemoizer<Target>>()};
std::shared_ptr<Target> CalculateTarget() const;
mutable util::ThreadSafeMemoizer<Target> memoized_target_;
// The corresponding aggregate Target of this Query instance. Unlike targets
// for non-aggregate queries, aggregate query targets do not contain
// normalized order-bys, they only contain explicit order-bys.
mutable std::shared_ptr<util::ThreadSafeMemoizer<Target>>
memoized_aggregate_target_{
std::make_shared<util::ThreadSafeMemoizer<Target>>()};
std::shared_ptr<Target> CalculateAggregateTarget() const;
mutable util::ThreadSafeMemoizer<Target> memoized_aggregate_target_;
};
bool operator==(const Query& lhs, const Query& rhs);

View File

@@ -112,7 +112,7 @@ void QueryListener::OnError(Status error) {
}
/**
* Returns whether a snaphsot was raised.
* Returns whether a snapshot was raised.
*/
bool QueryListener::OnOnlineStateChanged(OnlineState online_state) {
online_state_ = online_state;

View File

@@ -219,8 +219,7 @@ Target::IndexBoundValue Target::GetAscendingBound(
switch (field_filter.op()) {
case FieldFilter::Operator::LessThan:
case FieldFilter::Operator::LessThanOrEqual:
filter_value =
model::GetLowerBound(field_filter.value().which_value_type);
filter_value = model::GetLowerBound(field_filter.value());
break;
case FieldFilter::Operator::Equal:
case FieldFilter::Operator::In:
@@ -284,8 +283,7 @@ Target::IndexBoundValue Target::GetDescendingBound(
switch (field_filter.op()) {
case FieldFilter::Operator::GreaterThanOrEqual:
case FieldFilter::Operator::GreaterThan:
filter_value =
model::GetUpperBound(field_filter.value().which_value_type);
filter_value = model::GetUpperBound(field_filter.value());
filter_inclusive = false;
break;
case FieldFilter::Operator::Equal:

View File

@@ -24,7 +24,7 @@
#import <Foundation/Foundation.h>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <utility>

View File

@@ -24,7 +24,7 @@
#import <Foundation/Foundation.h>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <utility>
#include "Firestore/core/src/credentials/credentials_provider.h"

View File

@@ -18,7 +18,7 @@
#import "FirebaseCore/Extension/FIRAppInternal.h"
#import "FirebaseAuth/Interop/FIRAuthInterop.h"
#import "FirebaseAuth/Interop/Public/FirebaseAuthInterop/FIRAuthInterop.h"
#include "Firestore/core/src/util/error_apple.h"
#include "Firestore/core/src/util/hard_assert.h"

View File

@@ -47,8 +47,8 @@ auto KeysView(const Range& range) -> KeysRange<decltype(std::begin(range))> {
}
template <typename Range, typename K>
auto KeysViewFrom(const Range& range,
const K& key) -> KeysRange<decltype(range.lower_bound(key))> {
auto KeysViewFrom(const Range& range, const K& key)
-> KeysRange<decltype(range.lower_bound(key))> {
auto keys_begin = util::make_iterator_first(range.lower_bound(key));
auto keys_end = util::make_iterator_first(std::end(range));
return util::make_range(keys_begin, keys_end);

View File

@@ -21,6 +21,7 @@
#include <string>
#include "Firestore/core/src/model/resource_path.h"
#include "Firestore/core/src/model/value_util.h"
#include "Firestore/core/src/nanopb/nanopb_util.h"
namespace firebase {
@@ -46,6 +47,7 @@ enum IndexType {
kReference = 37,
kGeopoint = 45,
kArray = 50,
kVector = 53,
kMap = 55,
kReferenceSegment = 60,
// A terminator that indicates that a truncatable value was not truncated.
@@ -105,6 +107,31 @@ void WriteIndexArray(const google_firestore_v1_ArrayValue& array_index_value,
}
}
void WriteIndexVector(const google_firestore_v1_MapValue& map_index_value,
DirectionalIndexByteEncoder* encoder) {
WriteValueTypeLabel(encoder, IndexType::kVector);
absl::optional<pb_size_t> valueIndex =
model::IndexOfKey(map_index_value, model::kRawVectorValueFieldKey,
model::kVectorValueFieldKey);
if (!valueIndex.has_value() ||
map_index_value.fields[valueIndex.value()].value.which_value_type !=
google_firestore_v1_Value_array_value_tag) {
return WriteIndexArray(model::MinArray().array_value, encoder);
}
auto value = map_index_value.fields[valueIndex.value()].value;
// Vectors sort first by length
WriteValueTypeLabel(encoder, IndexType::kNumber);
encoder->WriteLong(value.array_value.values_count);
// Vectors then sort by position value
WriteIndexString(model::kVectorValueFieldKey, encoder);
WriteIndexValueAux(value, encoder);
}
void WriteIndexMap(google_firestore_v1_MapValue map_index_value,
DirectionalIndexByteEncoder* encoder) {
WriteValueTypeLabel(encoder, IndexType::kMap);
@@ -183,6 +210,9 @@ void WriteIndexValueAux(const google_firestore_v1_Value& index_value,
if (model::IsMaxValue(index_value)) {
WriteValueTypeLabel(encoder, std::numeric_limits<int>::max());
break;
} else if (model::IsVectorValue(index_value)) {
WriteIndexVector(index_value.map_value, encoder);
break;
}
WriteIndexMap(index_value.map_value, encoder);
WriteTruncationMarker(encoder);

View File

@@ -0,0 +1,57 @@
/**
* @license
* Copyright 2024 Google LLC
*
* 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.
*/
#ifndef FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_
#define FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_
#include "Firestore/core/src/nanopb/byte_string.h"
using firebase::firestore::nanopb::ByteString;
namespace firebase {
namespace firestore {
namespace local {
/**
* General purpose cache for global values.
*
* Global state that cuts across components should be saved here. Following are
* contained herein:
*
* `sessionToken` tracks server interaction across Listen and Write streams.
* This facilitates cache synchronization and invalidation.
*/
class GlobalsCache {
public:
virtual ~GlobalsCache() = default;
/**
* Gets session token.
*/
virtual ByteString GetSessionToken() const = 0;
/**
* Sets session token.
*/
virtual void SetSessionToken(const ByteString& session_token) = 0;
};
} // namespace local
} // namespace firestore
} // namespace firebase
#endif // FIRESTORE_CORE_SRC_LOCAL_GLOBALS_CACHE_H_

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2024 Google LLC
*
* 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.
*/
#include <string>
#include "Firestore/core/src/local/leveldb_globals_cache.h"
#include "Firestore/core/src/local/leveldb_key.h"
#include "Firestore/core/src/local/leveldb_persistence.h"
namespace firebase {
namespace firestore {
namespace local {
namespace {
const char* kSessionToken = "session_token";
}
LevelDbGlobalsCache::LevelDbGlobalsCache(LevelDbPersistence* db)
: db_(NOT_NULL(db)) {
}
ByteString LevelDbGlobalsCache::GetSessionToken() const {
auto key = LevelDbGlobalKey::Key(kSessionToken);
std::string encoded;
auto done = db_->current_transaction()->Get(key, &encoded);
if (!done.ok()) {
return ByteString();
}
return ByteString(encoded);
}
void LevelDbGlobalsCache::SetSessionToken(const ByteString& session_token) {
auto key = LevelDbGlobalKey::Key(kSessionToken);
db_->current_transaction()->Put(key, session_token.ToString());
}
} // namespace local
} // namespace firestore
} // namespace firebase

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2024 Google LLC
*
* 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.
*/
#ifndef FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_
#define FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_
#include "Firestore/core/src/local/globals_cache.h"
namespace firebase {
namespace firestore {
namespace local {
class LevelDbPersistence;
class LevelDbGlobalsCache : public GlobalsCache {
public:
/** Creates a new bundle cache in the given LevelDB. */
explicit LevelDbGlobalsCache(LevelDbPersistence* db);
/**
* Gets session token.
*/
ByteString GetSessionToken() const override;
/**
* Sets session token.
*/
void SetSessionToken(const ByteString& session_token) override;
private:
// The LevelDbGlobalsCache is owned by LevelDbPersistence.
LevelDbPersistence* db_ = nullptr;
};
} // namespace local
} // namespace firestore
} // namespace firebase
#endif // FIRESTORE_CORE_SRC_LOCAL_LEVELDB_GLOBALS_CACHE_H_

View File

@@ -188,10 +188,15 @@ LevelDbIndexManager::LevelDbIndexManager(const User& user,
// The contract for this comparison expected by priority queue is
// `std::less`, but std::priority_queue's default order is descending.
// We change the order to be ascending by doing left >= right instead.
// Note: priority queue has to have a strict ordering, so here using unique_id
// to order Field Indexes having same `sequence_number` and `collection_group`
auto cmp = [](FieldIndex* left, FieldIndex* right) {
if (left->index_state().sequence_number() ==
right->index_state().sequence_number()) {
return left->collection_group() >= right->collection_group();
if (left->collection_group() == right->collection_group()) {
return left->unique_id() > right->unique_id();
}
return left->collection_group() > right->collection_group();
}
return left->index_state().sequence_number() >
right->index_state().sequence_number();

View File

@@ -39,6 +39,7 @@ namespace local {
namespace {
const char* kVersionGlobalTable = "version";
const char* kGlobalsTable = "globals";
const char* kMutationsTable = "mutation";
const char* kDocumentMutationsTable = "document_mutation";
const char* kMutationQueuesTable = "mutation_queue";
@@ -159,6 +160,11 @@ enum ComponentLabel {
*/
DataMigrationName = 25,
/**
* The name of a global.
*/
GlobalName = 26,
/**
* A path segment describes just a single segment in a resource path. Path
* segments that occur sequentially in a key represent successive segments in
@@ -245,6 +251,10 @@ class Reader {
return ReadLabeledString(ComponentLabel::BundleId);
}
std::string ReadGlobalName() {
return ReadLabeledString(ComponentLabel::GlobalName);
}
std::string ReadQueryName() {
return ReadLabeledString(ComponentLabel::QueryName);
}
@@ -718,6 +728,10 @@ class Writer {
WriteLabeledString(ComponentLabel::TableName, table_name);
}
void WriteGlobalName(absl::string_view global_name) {
WriteLabeledString(ComponentLabel::GlobalName, global_name);
}
void WriteBatchId(model::BatchId batch_id) {
WriteLabeledInt32(ComponentLabel::BatchId, batch_id);
}
@@ -1206,6 +1220,28 @@ bool LevelDbRemoteDocumentReadTimeKey::Decode(absl::string_view key) {
return reader.ok();
}
std::string LevelDbGlobalKey::KeyPrefix() {
Writer writer;
writer.WriteTableName(kGlobalsTable);
return writer.result();
}
std::string LevelDbGlobalKey::Key(absl::string_view global_name) {
Writer writer;
writer.WriteTableName(kGlobalsTable);
writer.WriteGlobalName(global_name);
writer.WriteTerminator();
return writer.result();
}
bool LevelDbGlobalKey::Decode(absl::string_view key) {
Reader reader{key};
reader.ReadTableNameMatching(kGlobalsTable);
global_name_ = reader.ReadGlobalName();
reader.ReadTerminator();
return reader.ok();
}
std::string LevelDbBundleKey::KeyPrefix() {
Writer writer;
writer.WriteTableName(kBundlesTable);

View File

@@ -768,6 +768,41 @@ class LevelDbNamedQueryKey {
std::string name_;
};
/**
* A key in the globals table, storing the name of the global value.
*/
class LevelDbGlobalKey {
public:
/**
* Creates a key prefix that points just before the first key of the table.
*/
static std::string KeyPrefix();
/**
* Creates a key that points to the key for the given name of global value.
*/
static std::string Key(absl::string_view global_name);
/**
* Decodes the given complete key, storing the decoded values in this
* instance.
*
* @return true if the key successfully decoded, false otherwise. If false is
* returned, this instance is in an undefined state until the next call to
* `Decode()`.
*/
ABSL_MUST_USE_RESULT
bool Decode(absl::string_view key);
/** The name that serves as identifier for global value for this entry. */
const std::string& global_name() const {
return global_name_;
}
private:
std::string global_name_;
};
/**
* A key in the index_configuration table, storing the index definition proto,
* and the collection (group) it applies to.

View File

@@ -126,6 +126,7 @@ LevelDbPersistence::LevelDbPersistence(std::unique_ptr<leveldb::DB> db,
reference_delegate_ =
absl::make_unique<LevelDbLruReferenceDelegate>(this, lru_params);
bundle_cache_ = absl::make_unique<LevelDbBundleCache>(this, &serializer_);
globals_cache_ = absl::make_unique<LevelDbGlobalsCache>(this);
// TODO(gsoltis): set up a leveldb transaction for these operations.
target_cache_->Start();
@@ -250,6 +251,10 @@ LevelDbTargetCache* LevelDbPersistence::target_cache() {
return target_cache_.get();
}
LevelDbGlobalsCache* LevelDbPersistence::globals_cache() {
return globals_cache_.get();
}
LevelDbRemoteDocumentCache* LevelDbPersistence::remote_document_cache() {
return document_cache_.get();
}

View File

@@ -25,6 +25,7 @@
#include "Firestore/core/src/credentials/user.h"
#include "Firestore/core/src/local/leveldb_bundle_cache.h"
#include "Firestore/core/src/local/leveldb_document_overlay_cache.h"
#include "Firestore/core/src/local/leveldb_globals_cache.h"
#include "Firestore/core/src/local/leveldb_index_manager.h"
#include "Firestore/core/src/local/leveldb_lru_reference_delegate.h"
#include "Firestore/core/src/local/leveldb_migrations.h"
@@ -84,6 +85,8 @@ class LevelDbPersistence : public Persistence {
LevelDbBundleCache* bundle_cache() override;
LevelDbGlobalsCache* globals_cache() override;
LevelDbDocumentOverlayCache* GetDocumentOverlayCache(
const credentials::User& user) override;
LevelDbOverlayMigrationManager* GetOverlayMigrationManager(
@@ -154,6 +157,7 @@ class LevelDbPersistence : public Persistence {
bool started_ = false;
std::unique_ptr<LevelDbBundleCache> bundle_cache_;
std::unique_ptr<LevelDbGlobalsCache> globals_cache_;
std::unordered_map<std::string, std::unique_ptr<LevelDbDocumentOverlayCache>>
document_overlay_caches_;
std::unordered_map<std::string,

View File

@@ -17,7 +17,7 @@
#include "Firestore/core/src/local/leveldb_remote_document_cache.h"
#include <string>
#include <thread> // NOLINT(build/c++11)
#include <thread>
#include <utility>
#include "Firestore/Protos/nanopb/firestore/local/maybe_document.nanopb.h"

View File

@@ -19,7 +19,7 @@
#include <memory>
#include <string>
#include <thread> // NOLINT(build/c++11)
#include <thread>
#include <vector>
#include "Firestore/core/src/core/query.h"

View File

@@ -585,7 +585,7 @@ LruResults LocalStore::CollectGarbage(LruGarbageCollector* garbage_collector) {
});
}
int LocalStore::Backfill() const {
size_t LocalStore::Backfill() const {
return persistence_->Run("Backfill Indexes", [&] {
return index_backfiller_->WriteIndexEntries(this);
});

View File

@@ -254,7 +254,7 @@ class LocalStore : public bundle::BundleCallback {
* Runs a single backfill operation and returns the number of documents
* processed.
*/
int Backfill() const;
size_t Backfill() const;
/**
* Returns whether the given bundle has already been loaded and its create

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/local/lru_garbage_collector.h"
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <queue>
#include <string>
#include <utility>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 Google
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,20 @@
* limitations under the License.
*/
#import "FIRTimestamp.h"
#include "Firestore/core/src/local/memory_globals_cache.h"
NS_ASSUME_NONNULL_BEGIN
namespace firebase {
namespace firestore {
namespace local {
/** Internal FIRTimestamp API we don't want exposed in our public header files. */
@interface FIRTimestamp (Internal)
ByteString MemoryGlobalsCache::GetSessionToken() const {
return session_token_;
}
/**
* Converts the given date to an ISO 8601 timestamp string, useful for rendering in JSON.
*
* ISO 8601 dates times in UTC look like this: "1912-04-14T23:40:00.000000000Z".
*
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-date-time-string-format
*/
- (NSString *)ISO8601String;
void MemoryGlobalsCache::SetSessionToken(const ByteString& session_token) {
session_token_ = session_token;
}
@end
NS_ASSUME_NONNULL_END
} // namespace local
} // namespace firestore
} // namespace firebase

View File

@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2024 Google LLC
*
* 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.
*/
#ifndef FIRESTORE_CORE_SRC_LOCAL_MEMORY_GLOBALS_CACHE_H_
#define FIRESTORE_CORE_SRC_LOCAL_MEMORY_GLOBALS_CACHE_H_
#include <string>
#include "Firestore/core/src/local/globals_cache.h"
namespace firebase {
namespace firestore {
namespace local {
class MemoryGlobalsCache : public GlobalsCache {
public:
/**
* Gets session token.
*/
ByteString GetSessionToken() const override;
/**
* Sets session token.
*/
void SetSessionToken(const ByteString& session_token) override;
private:
ByteString session_token_;
};
} // namespace local
} // namespace firestore
} // namespace firebase
#endif // FIRESTORE_CORE_SRC_LOCAL_MEMORY_GLOBALS_CACHE_H_

View File

@@ -17,6 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_LOCAL_MEMORY_MUTATION_QUEUE_H_
#define FIRESTORE_CORE_SRC_LOCAL_MEMORY_MUTATION_QUEUE_H_
#include <deque>
#include <set>
#include <vector>
@@ -59,7 +60,7 @@ class MemoryMutationQueue : public MutationQueue {
void RemoveMutationBatch(const model::MutationBatch& batch) override;
std::vector<model::MutationBatch> AllMutationBatches() override {
return queue_;
return std::vector<model::MutationBatch>(queue_.begin(), queue_.end());
}
std::vector<model::MutationBatch> AllMutationBatchesAffectingDocumentKeys(
@@ -128,7 +129,7 @@ class MemoryMutationQueue : public MutationQueue {
* Once the held write acknowledgements become visible they are removed from
* the head of the queue along with any tombstones that follow.
*/
std::vector<model::MutationBatch> queue_;
std::deque<model::MutationBatch> queue_;
/**
* The next value to use when assigning sequential IDs to each mutation

View File

@@ -102,6 +102,10 @@ MemoryBundleCache* MemoryPersistence::bundle_cache() {
return &bundle_cache_;
}
MemoryGlobalsCache* MemoryPersistence::globals_cache() {
return &globals_cache_;
}
MemoryDocumentOverlayCache* MemoryPersistence::GetDocumentOverlayCache(
const User& user) {
auto iter = document_overlay_caches_.find(user);

View File

@@ -27,6 +27,7 @@
#include "Firestore/core/src/credentials/user.h"
#include "Firestore/core/src/local/memory_bundle_cache.h"
#include "Firestore/core/src/local/memory_document_overlay_cache.h"
#include "Firestore/core/src/local/memory_globals_cache.h"
#include "Firestore/core/src/local/memory_index_manager.h"
#include "Firestore/core/src/local/memory_mutation_queue.h"
#include "Firestore/core/src/local/memory_remote_document_cache.h"
@@ -90,6 +91,8 @@ class MemoryPersistence : public Persistence {
MemoryBundleCache* bundle_cache() override;
MemoryGlobalsCache* globals_cache() override;
MemoryDocumentOverlayCache* GetDocumentOverlayCache(
const credentials::User& user) override;
@@ -138,6 +141,8 @@ class MemoryPersistence : public Persistence {
MemoryBundleCache bundle_cache_;
MemoryGlobalsCache globals_cache_;
DocumentOverlayCaches document_overlay_caches_;
MemoryOverlayMigrationManager overlay_migration_manager_;

View File

@@ -36,6 +36,7 @@ namespace local {
class BundleCache;
class DocumentOverlayCache;
class GlobalsCache;
class IndexManager;
class MutationQueue;
class OverlayMigrationManager;
@@ -86,6 +87,11 @@ class Persistence {
/** Releases any resources held during eager shutdown. */
virtual void Shutdown() = 0;
/**
* Returns GlobalCache representing a general purpose cache for global values.
*/
virtual GlobalsCache* globals_cache() = 0;
/**
* Returns a MutationQueue representing the persisted mutations for the given
* user.

View File

@@ -150,8 +150,18 @@ class BasePath {
std::equal(begin(), end(), potential_child.begin());
}
/**
* Compares the current path against another Path object. Paths are compared
* segment by segment, prioritizing numeric IDs (e.g., "__id123__") in numeric
* ascending order, followed by string segments in lexicographical order.
*/
util::ComparisonResult CompareTo(const T& rhs) const {
return util::CompareContainer(segments_, rhs.segments_);
size_t min_size = std::min(size(), rhs.size());
for (size_t i = 0; i < min_size; ++i) {
auto cmp = CompareSegments(segments_[i], rhs.segments_[i]);
if (!util::Same(cmp)) return cmp;
}
return util::Compare(size(), rhs.size());
}
friend bool operator==(const BasePath& lhs, const BasePath& rhs) {
@@ -174,6 +184,38 @@ class BasePath {
private:
SegmentsT segments_;
static const size_t kNumericIdPrefixLength = 4;
static const size_t kNumericIdSuffixLength = 2;
static const size_t kNumericIdTotalOverhead =
kNumericIdPrefixLength + kNumericIdSuffixLength;
static util::ComparisonResult CompareSegments(const std::string& lhs,
const std::string& rhs) {
bool isLhsNumeric = IsNumericId(lhs);
bool isRhsNumeric = IsNumericId(rhs);
if (isLhsNumeric && !isRhsNumeric) {
return util::ComparisonResult::Ascending;
} else if (!isLhsNumeric && isRhsNumeric) {
return util::ComparisonResult::Descending;
} else if (isLhsNumeric && isRhsNumeric) {
return util::Compare(ExtractNumericId(lhs), ExtractNumericId(rhs));
} else {
return util::Compare(lhs, rhs);
}
}
static bool IsNumericId(const std::string& segment) {
return segment.size() > kNumericIdTotalOverhead &&
segment.substr(0, kNumericIdPrefixLength) == "__id" &&
segment.substr(segment.size() - kNumericIdSuffixLength) == "__";
}
static int64_t ExtractNumericId(const std::string& segment) {
return std::stol(segment.substr(kNumericIdPrefixLength,
segment.size() - kNumericIdSuffixLength));
}
};
} // namespace impl

View File

@@ -20,6 +20,8 @@ namespace firebase {
namespace firestore {
namespace model {
std::atomic<int> FieldIndex::ref_count_{0};
util::ComparisonResult Segment::CompareTo(const Segment& rhs) const {
auto result = field_path().CompareTo(rhs.field_path());
if (result != util::ComparisonResult::Same) {

View File

@@ -243,7 +243,9 @@ class FieldIndex {
static util::ComparisonResult SemanticCompare(const FieldIndex& left,
const FieldIndex& right);
FieldIndex() : index_id_(UnknownId()) {
FieldIndex()
: index_id_(UnknownId()),
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
}
FieldIndex(int32_t index_id,
@@ -253,7 +255,50 @@ class FieldIndex {
: index_id_(index_id),
collection_group_(std::move(collection_group)),
segments_(std::move(segments)),
state_(std::move(state)) {
state_(std::move(state)),
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
}
// Copy constructor
FieldIndex(const FieldIndex& other)
: index_id_(other.index_id_),
collection_group_(other.collection_group_),
segments_(other.segments_),
state_(other.state_),
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
}
// Copy assignment operator
FieldIndex& operator=(const FieldIndex& other) {
if (this != &other) {
index_id_ = other.index_id_;
collection_group_ = other.collection_group_;
segments_ = other.segments_;
state_ = other.state_;
unique_id_ = ref_count_.fetch_add(1, std::memory_order_acq_rel);
}
return *this;
}
// Move constructor
FieldIndex(FieldIndex&& other) noexcept
: index_id_(other.index_id_),
collection_group_(std::move(other.collection_group_)),
segments_(std::move(other.segments_)),
state_(std::move(other.state_)),
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
}
// Move assignment operator
FieldIndex& operator=(FieldIndex&& other) noexcept {
if (this != &other) {
index_id_ = other.index_id_;
collection_group_ = std::move(other.collection_group_);
segments_ = std::move(other.segments_);
state_ = std::move(other.state_);
unique_id_ = ref_count_.fetch_add(1, std::memory_order_acq_rel);
}
return *this;
}
/**
@@ -285,6 +330,14 @@ class FieldIndex {
/** Returns the ArrayContains/ArrayContainsAny segment for this index. */
absl::optional<Segment> GetArraySegment() const;
/**
* Returns the unique identifier for this object, ensuring a strict ordering
* in the priority queue's comparison function.
*/
int unique_id() const {
return unique_id_;
}
/**
* A type that can be used as the "Compare" template parameter of ordered
* collections to have the elements ordered using
@@ -308,6 +361,10 @@ class FieldIndex {
std::string collection_group_;
std::vector<Segment> segments_;
IndexState state_;
int unique_id_;
// TODO(C++17): Replace with inline static std::atomic<int> ref_count_ = 0;
static std::atomic<int> ref_count_;
};
inline bool operator==(const FieldIndex& lhs, const FieldIndex& rhs) {

View File

@@ -38,26 +38,33 @@
namespace firebase {
namespace firestore {
namespace model {
namespace {
using nanopb::Message;
using util::ComparisonResult;
/** The smallest reference value. */
pb_bytes_array_s* kMinimumReferenceValue =
nanopb::MakeBytesArray("projects//databases//documents/");
/** The field type of a maximum proto value. */
const char* kRawMaxValueFieldKey = "__type__";
pb_bytes_array_s* kMaxValueFieldKey =
nanopb::MakeBytesArray(kRawMaxValueFieldKey);
/** The field type of a special object type. */
const char* kRawTypeValueFieldKey = "__type__";
pb_bytes_array_s* kTypeValueFieldKey =
nanopb::MakeBytesArray(kRawTypeValueFieldKey);
/** The field value of a maximum proto value. */
const char* kRawMaxValueFieldValue = "__max__";
pb_bytes_array_s* kMaxValueFieldValue =
nanopb::MakeBytesArray(kRawMaxValueFieldValue);
} // namespace
/** The type of a VectorValue proto. */
const char* kRawVectorTypeFieldValue = "__vector__";
pb_bytes_array_s* kVectorTypeFieldValue =
nanopb::MakeBytesArray(kRawVectorTypeFieldValue);
using nanopb::Message;
using util::ComparisonResult;
/** The value key of a VectorValue proto. */
const char* kRawVectorValueFieldKey = "value";
pb_bytes_array_s* kVectorValueFieldKey =
nanopb::MakeBytesArray(kRawVectorValueFieldKey);
TypeOrder GetTypeOrder(const google_firestore_v1_Value& value) {
switch (value.which_value_type) {
@@ -94,6 +101,8 @@ TypeOrder GetTypeOrder(const google_firestore_v1_Value& value) {
return TypeOrder::kServerTimestamp;
} else if (IsMaxValue(value)) {
return TypeOrder::kMaxValue;
} else if (IsVectorValue(value)) {
return TypeOrder::kVector;
}
return TypeOrder::kMap;
}
@@ -253,6 +262,43 @@ ComparisonResult CompareMaps(const google_firestore_v1_MapValue& left,
return util::Compare(left_map->fields_count, right_map->fields_count);
}
ComparisonResult CompareVectors(const google_firestore_v1_Value& left,
const google_firestore_v1_Value& right) {
HARD_ASSERT(IsVectorValue(left) && IsVectorValue(right),
"Cannot compare non-vector values as vectors.");
absl::optional<pb_size_t> leftIndex =
IndexOfKey(left.map_value, kRawVectorValueFieldKey, kVectorValueFieldKey);
absl::optional<pb_size_t> rightIndex = IndexOfKey(
right.map_value, kRawVectorValueFieldKey, kVectorValueFieldKey);
pb_size_t leftArrayLength = 0;
google_firestore_v1_Value leftArray;
if (leftIndex.has_value()) {
leftArray = left.map_value.fields[leftIndex.value()].value;
leftArrayLength = leftArray.array_value.values_count;
}
pb_size_t rightArrayLength = 0;
google_firestore_v1_Value rightArray;
if (leftIndex.has_value()) {
rightArray = right.map_value.fields[rightIndex.value()].value;
rightArrayLength = rightArray.array_value.values_count;
}
if (leftArrayLength == 0 && rightArrayLength == 0) {
return ComparisonResult::Same;
}
ComparisonResult lengthCompare =
util::Compare(leftArrayLength, rightArrayLength);
if (lengthCompare != ComparisonResult::Same) {
return lengthCompare;
}
return CompareArrays(leftArray, rightArray);
}
ComparisonResult Compare(const google_firestore_v1_Value& left,
const google_firestore_v1_Value& right) {
TypeOrder left_type = GetTypeOrder(left);
@@ -297,6 +343,9 @@ ComparisonResult Compare(const google_firestore_v1_Value& left,
case TypeOrder::kMap:
return CompareMaps(left.map_value, right.map_value);
case TypeOrder::kVector:
return CompareVectors(left, right);
case TypeOrder::kMaxValue:
return util::ComparisonResult::Same;
@@ -425,6 +474,7 @@ bool Equals(const google_firestore_v1_Value& lhs,
case TypeOrder::kArray:
return ArrayEquals(lhs.array_value, rhs.array_value);
case TypeOrder::kVector:
case TypeOrder::kMap:
return MapValueEquals(lhs.map_value, rhs.map_value);
@@ -539,106 +589,87 @@ std::string CanonicalId(const google_firestore_v1_ArrayValue& value) {
return CanonifyArray(value);
}
google_firestore_v1_Value GetLowerBound(pb_size_t value_tag) {
switch (value_tag) {
google_firestore_v1_Value GetLowerBound(
const google_firestore_v1_Value& value) {
switch (value.which_value_type) {
case google_firestore_v1_Value_null_value_tag:
return NullValue();
case google_firestore_v1_Value_boolean_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.boolean_value = false;
return value;
return MinBoolean();
}
case google_firestore_v1_Value_integer_value_tag:
case google_firestore_v1_Value_double_value_tag: {
return NaNValue();
return MinNumber();
}
case google_firestore_v1_Value_timestamp_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.timestamp_value.seconds = std::numeric_limits<int64_t>::min();
value.timestamp_value.nanos = 0;
return value;
return MinTimestamp();
}
case google_firestore_v1_Value_string_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.string_value = nullptr;
return value;
return MinString();
}
case google_firestore_v1_Value_bytes_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.bytes_value = nullptr;
return value;
return MinBytes();
}
case google_firestore_v1_Value_reference_value_tag: {
google_firestore_v1_Value result;
result.which_value_type = google_firestore_v1_Value_reference_value_tag;
result.reference_value = kMinimumReferenceValue;
return result;
return MinReference();
}
case google_firestore_v1_Value_geo_point_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.geo_point_value.latitude = -90.0;
value.geo_point_value.longitude = -180.0;
return value;
return MinGeoPoint();
}
case google_firestore_v1_Value_array_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.array_value.values = nullptr;
value.array_value.values_count = 0;
return value;
return MinArray();
}
case google_firestore_v1_Value_map_value_tag: {
google_firestore_v1_Value value;
value.which_value_type = value_tag;
value.map_value.fields = nullptr;
value.map_value.fields_count = 0;
return value;
if (IsVectorValue(value)) {
return MinVector();
}
return MinMap();
}
default:
HARD_FAIL("Invalid type value: %s", value_tag);
HARD_FAIL("Invalid type value: %s", value.which_value_type);
}
}
google_firestore_v1_Value GetUpperBound(pb_size_t value_tag) {
switch (value_tag) {
google_firestore_v1_Value GetUpperBound(
const google_firestore_v1_Value& value) {
switch (value.which_value_type) {
case google_firestore_v1_Value_null_value_tag:
return GetLowerBound(google_protobuf_BoolValue_value_tag);
return MinBoolean();
case google_firestore_v1_Value_boolean_value_tag:
return GetLowerBound(google_firestore_v1_Value_integer_value_tag);
return MinNumber();
case google_firestore_v1_Value_integer_value_tag:
case google_firestore_v1_Value_double_value_tag:
return GetLowerBound(google_firestore_v1_Value_timestamp_value_tag);
return MinTimestamp();
case google_firestore_v1_Value_timestamp_value_tag:
return GetLowerBound(google_firestore_v1_Value_string_value_tag);
return MinString();
case google_firestore_v1_Value_string_value_tag:
return GetLowerBound(google_firestore_v1_Value_bytes_value_tag);
return MinBytes();
case google_firestore_v1_Value_bytes_value_tag:
return GetLowerBound(google_firestore_v1_Value_reference_value_tag);
return MinReference();
case google_firestore_v1_Value_reference_value_tag:
return GetLowerBound(google_firestore_v1_Value_geo_point_value_tag);
return MinGeoPoint();
case google_firestore_v1_Value_geo_point_value_tag:
return GetLowerBound(google_firestore_v1_Value_array_value_tag);
return MinArray();
case google_firestore_v1_Value_array_value_tag:
return GetLowerBound(google_firestore_v1_Value_map_value_tag);
return MinVector();
case google_firestore_v1_Value_map_value_tag:
if (IsVectorValue(value)) {
return MinMap();
}
return MaxValue();
default:
HARD_FAIL("Invalid type value: %s", value_tag);
HARD_FAIL("Invalid type value: %s", value.which_value_type);
}
}
@@ -693,7 +724,7 @@ google_firestore_v1_Value MaxValue() {
"google_firestore_v1_MapValue_FieldsEntry should be "
"trivially-destructible; otherwise, it should use NoDestructor below.");
static google_firestore_v1_MapValue_FieldsEntry field_entry;
field_entry.key = kMaxValueFieldKey;
field_entry.key = kTypeValueFieldKey;
field_entry.value = value;
google_firestore_v1_MapValue map_value;
@@ -718,9 +749,9 @@ bool IsMaxValue(const google_firestore_v1_Value& value) {
// Comparing the pointer address, then actual content if addresses are
// different.
if (value.map_value.fields[0].key != kMaxValueFieldKey &&
if (value.map_value.fields[0].key != kTypeValueFieldKey &&
nanopb::MakeStringView(value.map_value.fields[0].key) !=
kRawMaxValueFieldKey) {
kRawTypeValueFieldKey) {
return false;
}
@@ -736,6 +767,65 @@ bool IsMaxValue(const google_firestore_v1_Value& value) {
kRawMaxValueFieldValue;
}
absl::optional<pb_size_t> IndexOfKey(
const google_firestore_v1_MapValue& mapValue,
const char* kRawTypeValueFieldKey,
pb_bytes_array_s* kTypeValueFieldKey) {
for (pb_size_t i = 0; i < mapValue.fields_count; i++) {
if (mapValue.fields[i].key == kTypeValueFieldKey ||
nanopb::MakeStringView(mapValue.fields[i].key) ==
kRawTypeValueFieldKey) {
return i;
}
}
return absl::nullopt;
}
bool IsVectorValue(const google_firestore_v1_Value& value) {
if (value.which_value_type != google_firestore_v1_Value_map_value_tag) {
return false;
}
if (value.map_value.fields_count < 2) {
return false;
}
absl::optional<pb_size_t> typeFieldIndex =
IndexOfKey(value.map_value, kRawTypeValueFieldKey, kTypeValueFieldKey);
if (!typeFieldIndex.has_value()) {
return false;
}
if (value.map_value.fields[typeFieldIndex.value()].value.which_value_type !=
google_firestore_v1_Value_string_value_tag) {
return false;
}
// Comparing the pointer address, then actual content if addresses are
// different.
if (value.map_value.fields[typeFieldIndex.value()].value.string_value !=
kVectorTypeFieldValue &&
nanopb::MakeStringView(
value.map_value.fields[typeFieldIndex.value()].value.string_value) !=
kRawVectorTypeFieldValue) {
return false;
}
absl::optional<pb_size_t> valueFieldIndex = IndexOfKey(
value.map_value, kRawVectorValueFieldKey, kVectorValueFieldKey);
if (!valueFieldIndex.has_value()) {
return false;
}
if (value.map_value.fields[valueFieldIndex.value()].value.which_value_type !=
google_firestore_v1_Value_array_value_tag) {
return false;
}
return true;
}
google_firestore_v1_Value NaNValue() {
google_firestore_v1_Value nan_value;
nan_value.which_value_type = google_firestore_v1_Value_double_value_tag;
@@ -748,6 +838,98 @@ bool IsNaNValue(const google_firestore_v1_Value& value) {
std::isnan(value.double_value);
}
google_firestore_v1_Value MinBoolean() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_boolean_value_tag;
lowerBound.boolean_value = false;
return lowerBound;
}
google_firestore_v1_Value MinNumber() {
return NaNValue();
}
google_firestore_v1_Value MinTimestamp() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_timestamp_value_tag;
lowerBound.timestamp_value.seconds = std::numeric_limits<int64_t>::min();
lowerBound.timestamp_value.nanos = 0;
return lowerBound;
}
google_firestore_v1_Value MinString() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_string_value_tag;
lowerBound.string_value = nullptr;
return lowerBound;
}
google_firestore_v1_Value MinBytes() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_bytes_value_tag;
lowerBound.bytes_value = nullptr;
return lowerBound;
}
google_firestore_v1_Value MinReference() {
google_firestore_v1_Value result;
result.which_value_type = google_firestore_v1_Value_reference_value_tag;
result.reference_value = kMinimumReferenceValue;
return result;
}
google_firestore_v1_Value MinGeoPoint() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_geo_point_value_tag;
lowerBound.geo_point_value.latitude = -90.0;
lowerBound.geo_point_value.longitude = -180.0;
return lowerBound;
}
google_firestore_v1_Value MinArray() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_array_value_tag;
lowerBound.array_value.values = nullptr;
lowerBound.array_value.values_count = 0;
return lowerBound;
}
google_firestore_v1_Value MinVector() {
google_firestore_v1_Value typeValue;
typeValue.which_value_type = google_firestore_v1_Value_string_value_tag;
typeValue.string_value = kVectorTypeFieldValue;
google_firestore_v1_MapValue_FieldsEntry* field_entries =
nanopb::MakeArray<google_firestore_v1_MapValue_FieldsEntry>(2);
field_entries[0].key = kTypeValueFieldKey;
field_entries[0].value = typeValue;
google_firestore_v1_Value arrayValue;
arrayValue.which_value_type = google_firestore_v1_Value_array_value_tag;
arrayValue.array_value.values = nullptr;
arrayValue.array_value.values_count = 0;
field_entries[1].key = kVectorValueFieldKey;
field_entries[1].value = arrayValue;
google_firestore_v1_MapValue map_value;
map_value.fields_count = 2;
map_value.fields = field_entries;
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_map_value_tag;
lowerBound.map_value = map_value;
return lowerBound;
}
google_firestore_v1_Value MinMap() {
google_firestore_v1_Value lowerBound;
lowerBound.which_value_type = google_firestore_v1_Value_map_value_tag;
lowerBound.map_value.fields = nullptr;
lowerBound.map_value.fields_count = 0;
return lowerBound;
}
Message<google_firestore_v1_Value> RefValue(
const model::DatabaseId& database_id,
const model::DocumentKey& document_key) {

View File

@@ -23,6 +23,7 @@
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
#include "Firestore/core/src/nanopb/message.h"
#include "Firestore/core/src/nanopb/nanopb_util.h"
#include "absl/types/optional.h"
namespace firebase {
@@ -37,6 +38,25 @@ namespace model {
class DocumentKey;
class DatabaseId;
/** The smallest reference value. */
extern pb_bytes_array_s* kMinimumReferenceValue;
/** The field type of a special object type. */
extern const char* kRawTypeValueFieldKey;
extern pb_bytes_array_s* kTypeValueFieldKey;
/** The field value of a maximum proto value. */
extern const char* kRawMaxValueFieldValue;
extern pb_bytes_array_s* kMaxValueFieldValue;
/** The type of a VectorValue proto. */
extern const char* kRawVectorTypeFieldValue;
extern pb_bytes_array_s* kVectorTypeFieldValue;
/** The value key of a VectorValue proto. */
extern const char* kRawVectorValueFieldKey;
extern pb_bytes_array_s* kVectorValueFieldKey;
/**
* The order of types in Firestore. This order is based on the backend's
* ordering, but modified to support server timestamps.
@@ -52,8 +72,9 @@ enum class TypeOrder {
kReference = 7,
kGeoPoint = 8,
kArray = 9,
kMap = 10,
kMaxValue = 11
kVector = 10,
kMap = 11,
kMaxValue = 12
};
/** Returns the backend's type order of the given Value type. */
@@ -94,7 +115,7 @@ std::string CanonicalId(const google_firestore_v1_Value& value);
* The returned value might point to heap allocated memory that is owned by
* this function. To take ownership of this memory, call `DeepClone`.
*/
google_firestore_v1_Value GetLowerBound(pb_size_t value_tag);
google_firestore_v1_Value GetLowerBound(const google_firestore_v1_Value& value);
/**
* Returns the largest value for the given value type (exclusive).
@@ -102,7 +123,7 @@ google_firestore_v1_Value GetLowerBound(pb_size_t value_tag);
* The returned value might point to heap allocated memory that is owned by
* this function. To take ownership of this memory, call `DeepClone`.
*/
google_firestore_v1_Value GetUpperBound(pb_size_t value_tag);
google_firestore_v1_Value GetUpperBound(const google_firestore_v1_Value& value);
/**
* Generates the canonical ID for the provided array value (as used in Target
@@ -155,6 +176,22 @@ google_firestore_v1_Value MaxValue();
*/
bool IsMaxValue(const google_firestore_v1_Value& value);
/**
* Returns `true` if `value` represents a VectorValue..
*/
bool IsVectorValue(const google_firestore_v1_Value& value);
/**
* Returns the index of the specified key (`kRawTypeValueFieldKey`) in the
* map (`mapValue`). `kTypeValueFieldKey` is an alternative representation
* of the key specified in `kRawTypeValueFieldKey`.
* If the key is not found, then `absl::nullopt` is returned.
*/
absl::optional<pb_size_t> IndexOfKey(
const google_firestore_v1_MapValue& mapValue,
const char* kRawTypeValueFieldKey,
pb_bytes_array_s* kTypeValueFieldKey);
/**
* Returns `NaN` in its Protobuf representation.
*
@@ -166,6 +203,26 @@ google_firestore_v1_Value NaNValue();
/** Returns `true` if `value` is `NaN` in its Protobuf representation. */
bool IsNaNValue(const google_firestore_v1_Value& value);
google_firestore_v1_Value MinBoolean();
google_firestore_v1_Value MinNumber();
google_firestore_v1_Value MinTimestamp();
google_firestore_v1_Value MinString();
google_firestore_v1_Value MinBytes();
google_firestore_v1_Value MinReference();
google_firestore_v1_Value MinGeoPoint();
google_firestore_v1_Value MinArray();
google_firestore_v1_Value MinVector();
google_firestore_v1_Value MinMap();
/**
* Returns a Protobuf reference value representing the given location.
*

View File

@@ -17,7 +17,7 @@
#include "Firestore/core/src/nanopb/byte_string.h"
#include <cctype>
#include <cstdlib>
#include <cstdlib> // NOLINT(build/include_order)
#include <cstring>
#include <iomanip>
#include <ostream>

View File

@@ -179,6 +179,7 @@ inline NSData* _Nonnull MakeNSData(const ByteString& str) {
}
inline NSData* _Nonnull MakeNSData(const pb_bytes_array_t* _Nullable data) {
if (data == nil) return [[NSData alloc] init];
return [[NSData alloc] initWithBytes:data->bytes length:data->size];
}

View File

@@ -18,8 +18,7 @@
#if defined(__APPLE__)
#if TARGET_OS_IOS || TARGET_OS_TV || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
#import <UIKit/UIKit.h>
#endif
@@ -50,7 +49,7 @@ NetworkStatus ToNetworkStatus(SCNetworkReachabilityFlags flags) {
return NetworkStatus::Unavailable;
}
#if TARGET_OS_IPHONE || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IPHONE || TARGET_OS_VISION
if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
return NetworkStatus::AvailableViaCellular;
}
@@ -113,8 +112,7 @@ class ConnectivityMonitorApple : public ConnectivityMonitor {
return;
}
#if TARGET_OS_IOS || TARGET_OS_TV || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
this->observer_ = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
@@ -126,8 +124,7 @@ class ConnectivityMonitorApple : public ConnectivityMonitor {
}
~ConnectivityMonitorApple() {
#if TARGET_OS_IOS || TARGET_OS_TV || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
[[NSNotificationCenter defaultCenter] removeObserver:this->observer_];
#endif
@@ -142,8 +139,7 @@ class ConnectivityMonitorApple : public ConnectivityMonitor {
}
}
#if TARGET_OS_IOS || TARGET_OS_TV || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
void OnEnteredForeground() {
SCNetworkReachabilityFlags flags{};
if (!SCNetworkReachabilityGetFlags(reachability_, &flags)) return;
@@ -171,8 +167,7 @@ class ConnectivityMonitorApple : public ConnectivityMonitor {
private:
SCNetworkReachabilityRef reachability_ = nil;
#if TARGET_OS_IOS || TARGET_OS_TV || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
id<NSObject> observer_ = nil;
#endif
};

View File

@@ -17,7 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_REMOTE_EXPONENTIAL_BACKOFF_H_
#define FIRESTORE_CORE_SRC_REMOTE_EXPONENTIAL_BACKOFF_H_
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <memory>
#include "Firestore/core/src/util/async_queue.h"

View File

@@ -18,7 +18,7 @@
#import "FirebaseCore/Extension/FIRAppInternal.h"
#import "FirebaseCore/Extension/FIRHeartbeatLogger.h"
#import "FirebaseCore/Extension/FIROptionsInternal.h"
#import "FirebaseCore/Sources/FIROptionsInternal.h"
#include "Firestore/core/src/util/string_apple.h"

View File

@@ -17,9 +17,9 @@
#ifndef FIRESTORE_CORE_SRC_REMOTE_GRPC_COMPLETION_H_
#define FIRESTORE_CORE_SRC_REMOTE_GRPC_COMPLETION_H_
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <functional>
#include <future> // NOLINT(build/c++11)
#include <future>
#include <memory>
#include <utility>

View File

@@ -19,7 +19,7 @@
#include <cstdlib>
#include <algorithm>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <utility>

View File

@@ -16,8 +16,8 @@
#include "Firestore/core/src/remote/grpc_stream.h"
#include <chrono> // NOLINT(build/c++11)
#include <future> // NOLINT(build/c++11)
#include <chrono>
#include <future>
#include "Firestore/core/src/remote/grpc_connection.h"
#include "Firestore/core/src/remote/grpc_util.h"
@@ -98,7 +98,7 @@ GrpcStream::GrpcStream(
}
GrpcStream::~GrpcStream() {
LOG_DEBUG("GrpcStream('%s'): destroying stream", this);
LOG_DEBUG("GrpcStream('%x'): destroying stream", this);
HARD_ASSERT(completions_.empty(),
"GrpcStream is being destroyed without proper shutdown");
MaybeUnregister();
@@ -160,14 +160,14 @@ void GrpcStream::MaybeWrite(absl::optional<BufferedWrite> maybe_write) {
}
void GrpcStream::FinishImmediately() {
LOG_DEBUG("GrpcStream('%s'): finishing without notifying observers", this);
LOG_DEBUG("GrpcStream('%x'): finishing without notifying observers", this);
Shutdown();
UnsetObserver();
}
void GrpcStream::FinishAndNotify(const Status& status) {
LOG_DEBUG("GrpcStream('%s'): finishing and notifying observers", this);
LOG_DEBUG("GrpcStream('%x'): finishing and notifying observers", this);
Shutdown();
@@ -181,7 +181,7 @@ void GrpcStream::FinishAndNotify(const Status& status) {
}
void GrpcStream::Shutdown() {
LOG_DEBUG("GrpcStream('%s'): shutting down; completions: %s, is finished: %s",
LOG_DEBUG("GrpcStream('%x'): shutting down; completions: %s, is finished: %s",
this, completions_.size(), is_grpc_call_finished_);
MaybeUnregister();
@@ -216,7 +216,7 @@ void GrpcStream::MaybeUnregister() {
}
void GrpcStream::FinishGrpcCall(const OnSuccess& callback) {
LOG_DEBUG("GrpcStream('%s'): finishing the underlying call", this);
LOG_DEBUG("GrpcStream('%x'): finishing the underlying call", this);
HARD_ASSERT(!is_grpc_call_finished_, "FinishGrpcCall called twice");
is_grpc_call_finished_ = true;
@@ -229,7 +229,7 @@ void GrpcStream::FinishGrpcCall(const OnSuccess& callback) {
}
void GrpcStream::FastFinishCompletionsBlocking() {
LOG_DEBUG("GrpcStream('%s'): fast finishing %s completion(s)", this,
LOG_DEBUG("GrpcStream('%x'): fast finishing %s completion(s)", this,
completions_.size());
// TODO(varconst): reset buffered_writer_? Should not be necessary, because it
@@ -344,7 +344,7 @@ std::shared_ptr<GrpcCompletion> GrpcStream::NewCompletion(
} else {
// Use the same error-handling for all operations; all errors are
// unrecoverable.
LOG_DEBUG("GrpcStream('%s'): operation of type %s failed", this,
LOG_DEBUG("GrpcStream('%x'): operation of type %s failed", this,
completion->type());
OnOperationFailed();
}

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/remote/online_state_tracker.h"
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include "Firestore/core/src/util/executor.h"
#include "Firestore/core/src/util/hard_assert.h"

View File

@@ -85,14 +85,14 @@ void RemoteStore::Start() {
[this](ConnectivityMonitor::NetworkStatus network_status) {
if (network_status == ConnectivityMonitor::NetworkStatus::Unavailable) {
LOG_DEBUG(
"RemoteStore %s ignoring connectivity callback for unavailable "
"RemoteStore %x ignoring connectivity callback for unavailable "
"network",
this);
return;
}
if (CanUseNetwork()) {
LOG_DEBUG("RemoteStore %s restarting streams as connectivity changed",
LOG_DEBUG("RemoteStore %x restarting streams as connectivity changed",
this);
RestartNetwork();
}
@@ -139,7 +139,7 @@ void RemoteStore::DisableNetworkInternal() {
}
void RemoteStore::Shutdown() {
LOG_DEBUG("RemoteStore %s shutting down", this);
LOG_DEBUG("RemoteStore %x shutting down", this);
is_network_enabled_ = false;
DisableNetworkInternal();
@@ -514,7 +514,7 @@ void RemoteStore::HandleHandshakeError(const Status& status) {
if (Datastore::IsPermanentError(status)) {
std::string token = util::ToString(write_stream_->last_stream_token());
LOG_DEBUG(
"RemoteStore %s error before completed handshake; resetting "
"RemoteStore %x error before completed handshake; resetting "
"stream token %s: "
"error code: '%s', details: '%s'",
this, token, status.code(), status.error_message());
@@ -590,7 +590,7 @@ void RemoteStore::HandleCredentialChange() {
// Tear down and re-create our network streams. This will ensure we get a
// fresh auth token for the new user and re-fill the write pipeline with new
// mutations from the `LocalStore` (since mutations are per-user).
LOG_DEBUG("RemoteStore %s restarting streams for new credential", this);
LOG_DEBUG("RemoteStore %x restarting streams for new credential", this);
RestartNetwork();
}
}

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/remote/stream.h"
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <utility>
#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
@@ -380,7 +380,7 @@ void Stream::Write(grpc::ByteBuffer&& message) {
std::string Stream::GetDebugDescription() const {
EnsureOnQueue();
return StringFormat("%s (%s)", GetDebugName(), this);
return StringFormat("%s (%x)", GetDebugName(), this);
}
} // namespace remote

View File

@@ -56,7 +56,7 @@ class WatchStreamCallback {
/**
* Called by the `WatchStream` with changes and the snapshot versions
* included in in the `WatchChange` responses sent back by the server.
* included in the `WatchChange` responses sent back by the server.
*/
virtual void OnWatchStreamChange(
const WatchChange& change,

View File

@@ -20,8 +20,6 @@
#if defined(__APPLE__)
#import <CoreFoundation/CoreFoundation.h>
#elif defined(_STLPORT_VERSION)
#include <ctime>
#endif
#include "Firestore/core/src/util/hard_assert.h"
@@ -76,29 +74,16 @@ Timestamp Timestamp::Now() {
auto nanos = static_cast<int32_t>(fraction * kNanosPerSecond);
return MakeNormalizedTimestamp(seconds, nanos);
#elif !defined(_STLPORT_VERSION)
// Use the standard <chrono> library from C++11 if possible.
return FromTimePoint(std::chrono::system_clock::now());
#else
// If <chrono> is unavailable, use clock_gettime from POSIX, which supports
// up to nanosecond resolution. Note that it's a non-standard function
// contained in <time.h>.
//
// Note: it's possible to check for availability of POSIX clock_gettime using
// macros (see "Availability" at https://linux.die.net/man/3/clock_gettime).
// However, the only platform where <chrono> isn't available is Android with
// STLPort standard library, where clock_gettime is known to be available.
timespec now;
clock_gettime(CLOCK_REALTIME, &now);
return MakeNormalizedTimestamp(now.tv_sec, now.tv_nsec);
#endif // !defined(_STLPORT_VERSION)
// Use the standard <chrono> library from C++11.
return FromTimePoint(std::chrono::system_clock::now());
#endif // defined(__APPLE__)
}
Timestamp Timestamp::FromTimeT(const time_t seconds_since_unix_epoch) {
return {seconds_since_unix_epoch, 0};
}
#if !defined(_STLPORT_VERSION)
Timestamp Timestamp::FromTimePoint(
const std::chrono::time_point<std::chrono::system_clock> time_point) {
namespace chr = std::chrono;
@@ -111,8 +96,6 @@ Timestamp Timestamp::FromTimePoint(
return result;
}
#endif // !defined(_STLPORT_VERSION)
std::string Timestamp::ToString() const {
return absl::StrCat("Timestamp(seconds=", seconds_,
", nanoseconds=", nanoseconds_, ")");

View File

@@ -18,10 +18,10 @@
#define FIRESTORE_CORE_SRC_UTIL_ASYNC_QUEUE_H_
#include <atomic>
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <functional>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <vector>
#include "Firestore/core/src/util/executor.h"

View File

@@ -17,9 +17,9 @@
#ifndef FIRESTORE_CORE_SRC_UTIL_BACKGROUND_QUEUE_H_
#define FIRESTORE_CORE_SRC_UTIL_BACKGROUND_QUEUE_H_
#include <condition_variable> // NOLINT(build/c++11)
#include <condition_variable>
#include <functional>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
namespace firebase {
namespace firestore {

View File

@@ -17,7 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_UTIL_EXECUTOR_H_
#define FIRESTORE_CORE_SRC_UTIL_EXECUTOR_H_
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <functional>
#include <memory>
#include <string>
@@ -84,7 +84,7 @@ class Executor {
// object prevents any tasks from running that could observe a partially
// destroyed object graph.
//
// Requirements for implementors:
// Requirements for implementers:
// * Dispose implementations must be idempotent.
// * Dispose implementations must exclude concurrent execution of other
// methods.

View File

@@ -19,11 +19,11 @@
#include <dispatch/dispatch.h>
#include <chrono> // NOLINT(build/c++11)
#include <condition_variable> // NOLINT(build/c++11)
#include <chrono>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/util/executor_std.h"
#include <future> // NOLINT(build/c++11)
#include <future>
#include <memory>
#include <sstream>

View File

@@ -19,12 +19,12 @@
#include <algorithm>
#include <atomic>
#include <condition_variable> // NOLINT(build/c++11)
#include <condition_variable>
#include <deque>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <thread> // NOLINT(build/c++11)
#include <thread>
#include <utility>
#include <vector>

View File

@@ -45,8 +45,7 @@ Status Filesystem::ExcludeFromBackups(const Path& dir) {
}
StatusOr<Path> Filesystem::AppDataDir(absl::string_view app_name) {
#if TARGET_OS_IOS || TARGET_OS_OSX || \
(defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION
NSArray<NSString*>* directories = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES);
return Path::FromNSString(directories[0]).AppendUtf8(app_name);
@@ -62,7 +61,7 @@ StatusOr<Path> Filesystem::AppDataDir(absl::string_view app_name) {
}
StatusOr<Path> Filesystem::LegacyDocumentsDir(absl::string_view app_name) {
#if TARGET_OS_IOS || (defined(TARGET_OS_VISION) && TARGET_OS_VISION)
#if TARGET_OS_IOS || TARGET_OS_VISION
NSArray<NSString*>* directories = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
return Path::FromNSString(directories[0]).AppendUtf8(app_name);

View File

@@ -132,7 +132,7 @@ Path Filesystem::TempDir() {
#if !__APPLE__
Status Filesystem::IsDirectory(const Path& path) {
struct stat buffer {};
struct stat buffer{};
if (::stat(path.c_str(), &buffer)) {
if (errno == ENOENT) {
// Expected common error case.
@@ -168,7 +168,7 @@ Status Filesystem::IsDirectory(const Path& path) {
}
StatusOr<int64_t> Filesystem::FileSize(const Path& path) {
struct stat st {};
struct stat st{};
if (::stat(path.c_str(), &st) == 0) {
return st.st_size;
} else {

View File

@@ -28,13 +28,11 @@
#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
#if defined(__ANDROID__)
// Abseil does not support STLPort, so avoid their config.h here.
//
// TODO(b/163140650): Remove once the Firebase support floor moves to NDK R18.
//
// Meanwhile, NDK R16b (the current minimum) includes Clang 5.0.3 and GCC 4.9.
// While Clang supports `__cpp_exceptions` at that version, GCC does not. Both
// support `__EXCEPTIONS`.
// The firebase-cpp-sdk has issues compiling Abseil on Android in some cases;
// therefore, use `__EXCEPTIONS`, which is known to be set by clang in Android
// NDK r21e, instead of using `ABSL_HAVE_EXCEPTIONS`. In the future, consider
// using `__cpp_exceptions` instead, as the internet seems to suggest that it
// is more reliable with modern c++ compilers, such as those in NDK r21e.
#if __EXCEPTIONS
#define FIRESTORE_HAVE_EXCEPTIONS 1
#endif

View File

@@ -190,8 +190,8 @@ auto RankedInvokeHash(const Range& range, HashChoice<3>)
* value can itself be hashed.
*/
template <typename K>
auto RankedInvokeHash(const absl::optional<K>& option,
HashChoice<4>) -> decltype(InvokeHash(*option)) {
auto RankedInvokeHash(const absl::optional<K>& option, HashChoice<4>)
-> decltype(InvokeHash(*option)) {
return option ? InvokeHash(*option) : -1171;
}
@@ -202,8 +202,8 @@ size_t RankedInvokeHash(K value, HashChoice<5>) {
}
template <typename K>
auto RankedInvokeHash(const std::unique_ptr<K>& ptr,
HashChoice<6>) -> decltype(InvokeHash(*ptr)) {
auto RankedInvokeHash(const std::unique_ptr<K>& ptr, HashChoice<6>)
-> decltype(InvokeHash(*ptr)) {
return ptr ? InvokeHash(*ptr) : 23631;
}

View File

@@ -35,39 +35,46 @@ namespace {
const FIRLoggerService kFIRLoggerFirestore = @"[FirebaseFirestore]";
// Translates a C++ LogLevel to the equivalent Objective-C FIRLoggerLevel
FIRLoggerLevel ToFIRLoggerLevel(LogLevel level) {
switch (level) {
case kLogLevelDebug:
return FIRLoggerLevelDebug;
case kLogLevelNotice:
return FIRLoggerLevelNotice;
case kLogLevelWarning:
return FIRLoggerLevelWarning;
case kLogLevelError:
return FIRLoggerLevelError;
default:
// Unsupported log level. FIRSetLoggerLevel will deal with it.
return static_cast<FIRLoggerLevel>(-1);
}
}
// Actually logs a message via FIRLogger. This must be a C varargs function
// so that we can call FIRLogBasic which takes a `va_list`.
void LogMessageV(LogLevel level, NSString* format, ...) {
va_list list;
va_start(list, format);
FIRLogBasic(ToFIRLoggerLevel(level), kFIRLoggerFirestore, @"I-FST000001",
format, list);
switch (level) {
case kLogLevelDebug:
FIRLogBasicDebug(kFIRLoggerFirestore, @"I-FST000001", format, list);
break;
case kLogLevelNotice:
FIRLogBasicNotice(kFIRLoggerFirestore, @"I-FST000001", format, list);
break;
case kLogLevelWarning:
FIRLogBasicWarning(kFIRLoggerFirestore, @"I-FST000001", format, list);
break;
case kLogLevelError:
FIRLogBasicError(kFIRLoggerFirestore, @"I-FST000001", format, list);
break;
}
va_end(list);
}
} // namespace
void LogSetLevel(LogLevel level) {
FIRSetLoggerLevel(ToFIRLoggerLevel(level));
switch (level) {
case kLogLevelDebug:
FIRSetLoggerLevelDebug();
break;
case kLogLevelNotice:
FIRSetLoggerLevelNotice();
break;
case kLogLevelWarning:
FIRSetLoggerLevelWarning();
break;
case kLogLevelError:
FIRSetLoggerLevelError();
break;
}
}
// Note that FIRLogger's default level can be changed by persisting a
@@ -81,7 +88,17 @@ void LogSetLevel(LogLevel level) {
// defaults write firestore_util_test /google/firebase/debug_mode NO
bool LogIsLoggable(LogLevel level) {
return FIRIsLoggableLevel(ToFIRLoggerLevel(level), false);
switch (level) {
case kLogLevelDebug:
return FIRIsLoggableLevelDebug();
case kLogLevelNotice:
return FIRIsLoggableLevelNotice();
case kLogLevelWarning:
return FIRIsLoggableLevelWarning();
case kLogLevelError:
return FIRIsLoggableLevelError();
}
return false;
}
void LogMessage(LogLevel level, const std::string& message) {

View File

@@ -18,9 +18,9 @@
#define FIRESTORE_CORE_SRC_UTIL_SCHEDULE_H_
#include <algorithm>
#include <condition_variable> // NOLINT(build/c++11)
#include <condition_variable>
#include <deque>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <vector>
#include "Firestore/core/src/util/executor.h"

View File

@@ -16,6 +16,10 @@
#include "Firestore/core/src/util/string_format.h"
#include <string>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
namespace firebase {
namespace firestore {
namespace util {
@@ -24,7 +28,13 @@ namespace internal {
static const char* kMissing = "<missing>";
static const char* kInvalid = "<invalid>";
std::string StringFormatPieces(
// Disable asan for this function because of the way it manages stack
// (nested closure) is flagged with stack underflow by clang on Ubuntu.
#if defined(_MSC_VER)
__declspec(no_sanitize_address) std::string StringFormatPieces(
#else
__attribute__((no_sanitize_address)) std::string StringFormatPieces(
#endif
const char* format, std::initializer_list<absl::string_view> pieces) {
std::string result;
@@ -33,7 +43,7 @@ std::string StringFormatPieces(
auto pieces_iter = pieces.begin();
auto pieces_end = pieces.end();
auto append_next_piece = [&](std::string* dest) {
auto append_next_string_piece = [&](std::string* dest) {
if (pieces_iter == pieces_end) {
dest->append(kMissing);
} else {
@@ -43,6 +53,17 @@ std::string StringFormatPieces(
}
};
auto append_next_hex_piece = [&](std::string* dest) {
if (pieces_iter == pieces_end) {
dest->append(kMissing);
} else {
std::string hex =
absl::BytesToHexString(absl::string_view(pieces_iter->data()));
dest->append(hex.data(), hex.size());
++pieces_iter;
}
};
auto append_specifier = [&](char spec) {
switch (spec) {
case '%':
@@ -51,7 +72,12 @@ std::string StringFormatPieces(
break;
case 's': {
append_next_piece(&result);
append_next_string_piece(&result);
break;
}
case 'x': {
append_next_hex_piece(&result);
break;
}

View File

@@ -62,11 +62,20 @@ struct FormatChoice<5> {};
* formatting of the value as an unsigned integer.
* * Otherwise the value is interpreted as anything absl::AlphaNum accepts.
*/
class FormatArg : public absl::AlphaNum {
class FormatArg final : public absl::AlphaNum {
public:
template <typename T>
FormatArg(T&& value) // NOLINT(runtime/explicit)
: FormatArg{std::forward<T>(value), internal::FormatChoice<0>{}} {
FormatArg(
T&& value,
// TODO(b/388888512) Remove the usage of StringifySink since it is not
// part of absl's public API. Moreover, subclassing AlphaNum is not
// supported either, so find a way to do this without these two caveats.
// See https://github.com/firebase/firebase-ios-sdk/pull/14331 for a
// partial proposal.
absl::strings_internal::StringifySink&& sink =
{}) // NOLINT(runtime/explicit)
: FormatArg{std::forward<T>(value), std::move(sink),
internal::FormatChoice<0>{}} {
}
private:
@@ -79,7 +88,9 @@ class FormatArg : public absl::AlphaNum {
*/
template <typename T,
typename = typename std::enable_if<std::is_same<bool, T>{}>::type>
FormatArg(T bool_value, internal::FormatChoice<0>)
FormatArg(T bool_value,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<0>)
: AlphaNum(bool_value ? "true" : "false") {
}
@@ -90,7 +101,9 @@ class FormatArg : public absl::AlphaNum {
template <
typename T,
typename = typename std::enable_if<objc::is_objc_pointer<T>{}>::type>
FormatArg(T object, internal::FormatChoice<1>)
FormatArg(T object,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<1>)
: AlphaNum(MakeStringView([object description])) {
}
@@ -98,7 +111,9 @@ class FormatArg : public absl::AlphaNum {
* Creates a FormatArg from any Objective-C Class type. Objective-C Class
* types are a special struct that aren't of a type derived from NSObject.
*/
FormatArg(Class object, internal::FormatChoice<1>)
FormatArg(Class object,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<1>)
: AlphaNum(MakeStringView(NSStringFromClass(object))) {
}
#endif
@@ -108,7 +123,10 @@ class FormatArg : public absl::AlphaNum {
* handled specially to avoid ambiguity with generic pointers, which are
* handled differently.
*/
FormatArg(std::nullptr_t, internal::FormatChoice<2>) : AlphaNum("null") {
FormatArg(std::nullptr_t,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<2>)
: AlphaNum("null") {
}
/**
@@ -116,7 +134,9 @@ class FormatArg : public absl::AlphaNum {
* handled specially to avoid ambiguity with generic pointers, which are
* handled differently.
*/
FormatArg(const char* string_value, internal::FormatChoice<3>)
FormatArg(const char* string_value,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<3>)
: AlphaNum(string_value == nullptr ? "null" : string_value) {
}
@@ -125,8 +145,11 @@ class FormatArg : public absl::AlphaNum {
* hexadecimal integer literal.
*/
template <typename T>
FormatArg(T* pointer_value, internal::FormatChoice<4>)
: AlphaNum(absl::Hex(reinterpret_cast<uintptr_t>(pointer_value))) {
FormatArg(T* pointer_value,
absl::strings_internal::StringifySink&& sink,
internal::FormatChoice<4>)
: AlphaNum(absl::Hex(reinterpret_cast<uintptr_t>(pointer_value)),
std::move(sink)) {
}
/**
@@ -134,7 +157,9 @@ class FormatArg : public absl::AlphaNum {
* absl::AlphaNum accepts.
*/
template <typename T>
FormatArg(T&& value, internal::FormatChoice<5>)
FormatArg(T&& value,
absl::strings_internal::StringifySink&&,
internal::FormatChoice<5>)
: AlphaNum(std::forward<T>(value)) {
}
};

View File

@@ -16,7 +16,7 @@
#include "Firestore/core/src/util/task.h"
#include <chrono> // NOLINT(build/c++11)
#include <chrono>
#include <cstdint>
#include <utility>

View File

@@ -18,10 +18,10 @@
#define FIRESTORE_CORE_SRC_UTIL_TASK_H_
#include <atomic>
#include <condition_variable> // NOLINT(build/c++11)
#include <condition_variable>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <thread> // NOLINT(build/c++11)
#include <mutex>
#include <thread>
#include "Firestore/core/src/util/executor.h"

View File

@@ -17,7 +17,7 @@
#include "Firestore/core/src/util/testing_hooks.h"
#include <functional>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <type_traits>
#include <unordered_map>
#include <utility>

View File

@@ -19,7 +19,7 @@
#include <functional>
#include <memory>
#include <mutex> // NOLINT(build/c++11)
#include <mutex>
#include <string>
#include <unordered_map>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,10 @@
#define FIRESTORE_CORE_SRC_UTIL_THREAD_SAFE_MEMOIZER_H_
#include <functional>
#include <mutex> // NOLINT(build/c++11)
#include <vector>
#include <memory>
#include <utility>
#include "Firestore/core/src/util/hard_assert.h"
namespace firebase {
namespace firestore {
@@ -28,51 +30,135 @@ namespace util {
/**
* Stores a memoized value in a manner that is safe to be shared between
* multiple threads.
*
* TODO(b/299933587) Make `ThreadSafeMemoizer` copyable and moveable.
*/
template <typename T>
class ThreadSafeMemoizer {
public:
ThreadSafeMemoizer() = default;
~ThreadSafeMemoizer() {
// Call `std::call_once` in order to synchronize with the "active"
// invocation of `memoize()`. Without this synchronization, there is a data
// race between this destructor, which "reads" `memoized_value_` to destroy
// it, and the write to `memoized_value_` done by the "active" invocation of
// `memoize()`.
std::call_once(once_, [&]() {});
/**
* Creates a new ThreadSafeMemoizer with no memoized value.
*/
ThreadSafeMemoizer() {
std::atomic_store(&memoized_, std::shared_ptr<T>());
}
// This class cannot be copied or moved, because it has `std::once_flag`
// member.
ThreadSafeMemoizer(const ThreadSafeMemoizer&) = delete;
ThreadSafeMemoizer(ThreadSafeMemoizer&&) = delete;
ThreadSafeMemoizer& operator=(const ThreadSafeMemoizer&) = delete;
ThreadSafeMemoizer& operator=(ThreadSafeMemoizer&&) = delete;
/**
* Copy constructor: creates a new ThreadSafeMemoizer object with the same
* memoized value as the ThreadSafeMemoizer object referred to by the given
* reference.
*
* The runtime performance of this function is O(1).
*/
ThreadSafeMemoizer(const ThreadSafeMemoizer& other) {
operator=(other);
}
/**
* Memoize a value.
* Copy assignment operator: replaces this object's memoized value with the
* memoized value of the ThreadSafeMemoizer object referred to by the given
* reference.
*
* The std::function object specified by the first invocation of this
* function (the "active" invocation) will be invoked synchronously.
* None of the std::function objects specified by the subsequent
* invocations of this function (the "passive" invocations) will be
* invoked. All invocations, both "active" and "passive", will return a
* reference to the std::vector created by copying the return value from
* the std::function specified by the "active" invocation. It is,
* therefore, the "active" invocation's job to return the std::vector
* to memoize.
* The runtime performance of this function is O(1).
*/
const T& memoize(std::function<T()> func) {
std::call_once(once_, [&]() { memoized_value_ = func(); });
return memoized_value_;
ThreadSafeMemoizer& operator=(const ThreadSafeMemoizer& other) {
if (&other == this) {
return *this;
}
std::atomic_store(&memoized_, std::atomic_load(&other.memoized_));
return *this;
}
/**
* Move constructor: creates a new ThreadSafeMemoizer object with the same
* memoized value as the ThreadSafeMemoizer object referred to by the given
* reference, also clearing its memoized value.
*
* The runtime performance of this function is O(1).
*/
ThreadSafeMemoizer(ThreadSafeMemoizer&& other) noexcept {
operator=(std::move(other));
}
/**
* Move assignment operator: replaces this object's memoized value with the
* memoized value of the ThreadSafeMemoizer object referred to by the given
* reference, also clearing its memoized value.
*
* The runtime performance of this function is O(1).
*/
ThreadSafeMemoizer& operator=(ThreadSafeMemoizer&& other) noexcept {
std::atomic_store(&memoized_, std::atomic_load(&other.memoized_));
std::atomic_store(&other.memoized_, std::shared_ptr<T>());
return *this;
}
/**
* Return the memoized value, calculating it with the given function if
* needed.
*
* If this object _does_ have a memoized value then this function simply
* returns a reference to it and does _not_ call the given function.
*
* On the other hand, if this object does _not_ have a memoized value then
* the given function is called to calculate the value to memoize. The value
* returned by the function is stored internally as the "memoized value" and
* then returned. If multiple threads race in calls to this function then
* more than one of them may have their functions called but only one of them
* will be memoized, with the others being discarded.
*
* The given function will be called synchronously by this function either
* zero times or one time. No reference to the given function is retained by
* this object.
*
* The given function _must_ return an initialized `std::shared_ptr<T>`; that
* is, the returned `std::shared_ptr<T>` _must_ evaluate to `true` when
* converted to `bool`. It is undefined behavior if the returned
* `std::shared_ptr<T>` does _not_ satisfy this requirement.
*
* This function is thread-safe and may be called concurrently by multiple
* threads.
*
* The returned reference is "valid" only as long as this `ThreadSafeMemoizer`
* object is alive; namely, once this `ThreadSafeMemoizer` object's destructor
* starts running, the reference returned by this function is invalid and
* using it is undefined behavior.
*/
const T& value(const std::function<std::shared_ptr<T>()>& func) {
std::shared_ptr<T> old_memoized = std::atomic_load(&memoized_);
std::shared_ptr<T> new_memoized;
bool new_memoized_is_initialized = false;
while (true) {
if (old_memoized) {
return *old_memoized;
}
if (!new_memoized_is_initialized) {
new_memoized = func();
new_memoized_is_initialized = true;
HARD_ASSERT(new_memoized);
}
if (std::atomic_compare_exchange_weak(&memoized_, &old_memoized,
new_memoized)) {
return *new_memoized;
}
}
}
private:
std::once_flag once_;
T memoized_value_;
// NOTE: Always use the std::atomic_XXX() functions to access the memoized_
// std::shared_ptr to ensure thread safety.
// See https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic.
// TODO(c++20): Use std::atomic<std::shared_ptr<T>> instead of a bare
// std::shared_ptr<T> and the std::atomic_XXX() functions. The
// std::atomic_XXX() free functions are deprecated in C++20, and are also
// more error-prone than their std::atomic<std::shared_ptr<T>> member
// function counterparts.
std::shared_ptr<T> memoized_;
};
} // namespace util

View File

@@ -5142,7 +5142,7 @@ auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N))
}
// This class only handles inputs of input_buffer_adapter type.
// It's required so that expressions like {ptr, len} can be implicitely casted
// It's required so that expressions like {ptr, len} can be implicitly casted
// to the correct adapter.
class span_input_adapter
{
@@ -9916,7 +9916,7 @@ class binary_reader
@return whether conversion completed
@note This function needs to respect the system's endianess, because
@note This function needs to respect the system's endianness, because
bytes in CBOR, MessagePack, and UBJSON are stored in network order
(big endian) and therefore need reordering on little endian systems.
*/
@@ -10088,7 +10088,7 @@ class binary_reader
/// the number of characters read
std::size_t chars_read = 0;
/// whether we can assume little endianess
/// whether we can assume little endianness
const bool is_little_endian = little_endianess();
/// the SAX parser
@@ -14227,7 +14227,7 @@ class binary_writer
@tparam OutputIsLittleEndian Set to true if output data is
required to be little endian
@note This function needs to respect the system's endianess, because bytes
@note This function needs to respect the system's endianness, because bytes
in CBOR, MessagePack, and UBJSON are stored in network order (big
endian) and therefore need reordering on little endian systems.
*/
@@ -14310,7 +14310,7 @@ class binary_writer
}
private:
/// whether we can assume little endianess
/// whether we can assume little endianness
const bool is_little_endian = little_endianess();
/// the output
@@ -21337,7 +21337,7 @@ class basic_json
`key()` returns an empty string.
@warning Using `items()` on temporary objects is dangerous. Make sure the
object's lifetime exeeds the iteration. See
object's lifetime exceeds the iteration. See
<https://github.com/nlohmann/json/issues/2040> for more
information.

View File

@@ -86,7 +86,7 @@ For details on using Firebase from a Framework or a library, refer to [firebase_
To develop Firebase software in this repository, ensure that you have at least
the following software:
* Xcode 14.1 (or later)
* Xcode 16.2 (or later)
CocoaPods is still the canonical way to develop, but much of the repo now supports
development with Swift Package Manager.
@@ -137,7 +137,7 @@ Alternatively, disable signing in each target:
### Adding a New Firebase Pod
Refer to [AddNewPod](AddNewPod.md) Markdown file for details.
Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details.
### Managing Headers and Imports
@@ -153,7 +153,7 @@ GitHub Actions will verify that any code changes are done in a style-compliant
way. Install `clang-format` and `mint`:
```console
brew install clang-format@18
brew install clang-format@20
brew install mint
```
@@ -235,6 +235,11 @@ at **Project Settings > Cloud Messaging > [Your Firebase App]**.
The iOS Simulator cannot register for remote notifications and will not receive push notifications.
To receive push notifications, follow the steps above and run the app on a physical device.
### Vertex AI for Firebase
See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for
instructions about building and testing the SDK.
## Building with Firebase on Apple platforms
Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS